Set up basic codes and CI.
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
new file mode 100644
index 0000000..a198b6c
--- /dev/null
+++ b/.github/workflows/ci.yaml
@@ -0,0 +1,29 @@
+name: CI AND IT
+
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+ tags:
+ - 'v*'
+
+
+jobs:
+ CI:
+ runs-on: ubuntu-18.04
+ timeout-minutes: 180
+ strategy:
+ fail-fast: true
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ submodules: true
+ - uses: actions-rs/cargo@v1
+ with:
+ command: build
+ args: --release --all-features
+ - name: 'Install & Test'
+ run: |
+ cargo build
+ cargo test
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..07827cc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target/
+.idea/
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..69a500f
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "skywalking-core"
+version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..007e2b9
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,5 @@
+[workspace]
+
+members = [
+ "tracing-core",
+]
\ No newline at end of file
diff --git a/README.md b/README.md
index ad3629d..205f5e9 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,9 @@
![CI](https://github.com/apache/skywalking-nginx-lua/workflows/CI/badge.svg?branch=master)
-[**SkyWalking**](https://github.com/apache/skywalking) Rust Agent provides tracing and metrics capability for Rust App and Library.
-It uses SkyWalking native formats and core concepts.
+[**SkyWalking**](https://github.com/apache/skywalking) Rust Agent provides observability capability for Rust App and Library,
+including tracing, metrics, topology map for distributed system and alert.
+It uses SkyWalking native formats and core concepts to keep best compatibility and performance.
# License
Apache 2.0
\ No newline at end of file
diff --git a/tracing-core/Cargo.toml b/tracing-core/Cargo.toml
new file mode 100644
index 0000000..ca95634
--- /dev/null
+++ b/tracing-core/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "skywalking-core"
+version = "0.1.0"
+authors = ["Apache Software Foundation (ASF)"]
+edition = "2018"
+description = "SkyWalking Rust Agent provides observability capability for Rust App and Library, including tracing, metrics, topology map for distributed system and alert."
+license = "Apache 2.0"
+
+[dependencies]
\ No newline at end of file
diff --git a/tracing-core/src/context.rs b/tracing-core/src/context.rs
new file mode 100644
index 0000000..17a43c4
--- /dev/null
+++ b/tracing-core/src/context.rs
@@ -0,0 +1,46 @@
+use crate::{Span, TracingSpan};
+
+/// Context represents the context of a tracing process.
+/// All new span belonging to this tracing context should be created through this context.
+pub trait Context<'a> {
+ /// Fetch the next id for new span
+ fn next_span_id(&mut self) -> i32;
+ fn create_entry_span(&mut self, operation_name: String, parent: Option<&dyn Span>) -> Box<dyn Span>;
+ fn create_exit_span(&mut self, operation_name: String, parent: Option<&dyn Span>) -> Box<dyn Span>;
+ fn create_local_span(&mut self, operation_name: String, parent: Option<&dyn Span>) -> Box<dyn Span>;
+}
+
+pub struct TracingContext {
+ /// Span id sequence. Indicate the number of created spans.
+ next_seq: i32,
+}
+
+impl TracingContext {
+ /// Create a new instance
+ pub fn new() -> Self {
+ TracingContext {
+ next_seq: -1
+ }
+ }
+}
+
+/// Default implementation of Context
+impl<'a> Context<'a> for TracingContext {
+ /// Fetch the next id for new span
+ fn next_span_id(&mut self) -> i32 {
+ self.next_seq = self.next_seq + 1;
+ self.next_seq
+ }
+
+ fn create_entry_span(&mut self, operation_name: String, parent: Option<&dyn Span>) -> Box<dyn Span> {
+ TracingSpan::new_entry_span(operation_name, self, parent)
+ }
+
+ fn create_exit_span(&mut self, operation_name: String, parent: Option<&dyn Span>) -> Box<dyn Span> {
+ TracingSpan::new_exit_span(operation_name, self, parent)
+ }
+
+ fn create_local_span(&mut self, operation_name: String, parent: Option<&dyn Span>) -> Box<dyn Span> {
+ TracingSpan::new_local_span(operation_name, self, parent)
+ }
+}
\ No newline at end of file
diff --git a/tracing-core/src/lib.rs b/tracing-core/src/lib.rs
new file mode 100644
index 0000000..4be7dcb
--- /dev/null
+++ b/tracing-core/src/lib.rs
@@ -0,0 +1,7 @@
+pub mod span;
+pub mod context;
+
+pub use span::TracingSpan;
+pub use span::Span;
+pub use context::TracingContext;
+pub use context::Context;
\ No newline at end of file
diff --git a/tracing-core/src/span.rs b/tracing-core/src/span.rs
new file mode 100644
index 0000000..c429e0c
--- /dev/null
+++ b/tracing-core/src/span.rs
@@ -0,0 +1,131 @@
+use std::time::SystemTime;
+
+use crate::Context;
+
+/// Span is one of the tracing concept, representing a time duration.
+/// Typically, it represent a method invocation or a RPC.
+pub trait Span {
+ fn start(&mut self);
+ fn start_with_timestamp(&mut self, timestamp: SystemTime);
+ fn is_entry(&self) -> bool;
+ fn is_exit(&self) -> bool;
+ fn span_id(&self) -> i32;
+}
+
+pub struct TracingSpan {
+ /// The operation name represents the logic process of this span
+ operation_name: String,
+ span_id: i32,
+ paren_span_id: i32,
+ /// The timestamp of the span start time
+ start_time: u64,
+ /// The timestamp of the span end time
+ end_time: u64,
+ /// As an entry span
+ is_entry: bool,
+ /// As an exit span
+ is_exit: bool,
+}
+
+impl TracingSpan {
+ /// Create a new entry span
+ pub fn new_entry_span(operation_name: String, context: &mut dyn Context, parent: Option<&dyn Span>) -> Box<dyn Span> {
+ let mut span = TracingSpan::_new(operation_name, context, parent);
+ span.is_entry = true;
+ Box::new(span)
+ }
+
+ /// Create a new exit span
+ pub fn new_exit_span(operation_name: String, context: &mut dyn Context, parent: Option<&dyn Span>) -> Box<dyn Span> {
+ let mut span = TracingSpan::_new(operation_name, context, parent);
+ span.is_exit = true;
+ Box::new(span)
+ }
+
+ /// Create a new local span
+ pub fn new_local_span(operation_name: String, context: &mut dyn Context, parent: Option<&dyn Span>) -> Box<dyn Span> {
+ let span = TracingSpan::_new(operation_name, context, parent);
+ Box::new(span)
+ }
+
+ /// Create a span and set the limited internal values
+ fn _new(operation_name: String, context: &mut dyn Context, parent: Option<&Span>) -> Self {
+ TracingSpan {
+ operation_name: operation_name.clone(),
+ span_id: context.next_span_id(),
+ paren_span_id: match parent {
+ // -1 means no parent span
+ None => { -1 }
+ Some(parent) => { parent.span_id() }
+ },
+ start_time: 0,
+ end_time: 0,
+ is_entry: false,
+ is_exit: false,
+ }
+ }
+}
+
+impl Span for TracingSpan {
+ fn start(&mut self) {
+ self.start_time = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
+ Ok(n) => { n.as_millis() }
+ Err(_) => self.start_time as u128,
+ } as u64;
+ }
+
+ fn start_with_timestamp(&mut self, timestamp: SystemTime) {
+ self.start_time = match timestamp.duration_since(SystemTime::UNIX_EPOCH) {
+ Ok(n) => { n.as_millis() }
+ Err(_) => self.start_time as u128,
+ } as u64;
+ }
+
+ fn is_entry(&self) -> bool {
+ self.is_entry
+ }
+
+ fn is_exit(&self) -> bool {
+ self.is_exit
+ }
+
+ fn span_id(&self) -> i32 {
+ self.span_id
+ }
+}
+
+#[cfg(test)]
+mod span_tests {
+ use std::time::SystemTime;
+
+ use crate::span::*;
+ use crate::TracingContext;
+
+ #[test]
+ fn test_span_new() {
+ let mut context = TracingContext::new();
+ let mut span = TracingSpan::_new(String::from("op1"), &mut context, None);
+ assert_eq!(span.paren_span_id, -1);
+ assert_eq!(span.span_id, 0);
+ assert_eq!(span.start_time, 0);
+ span.start();
+ assert_ne!(span.start_time, 0);
+
+ let mut span2 = TracingSpan::_new(String::from("op2"), &mut context, Some(&span));
+ assert_eq!("op2", span2.operation_name);
+ assert_eq!(span2.paren_span_id, 0);
+ assert_eq!(span2.span_id, 1);
+ span2.start_with_timestamp(SystemTime::now());
+ assert_ne!(span2.start_time, 0);
+ }
+
+ #[test]
+ fn test_new_entry_span() {
+ let mut context = TracingContext::new();
+ let mut span = TracingSpan::new_entry_span(String::from("op1"), &mut context, None);
+ assert_eq!(span.is_entry(), true)
+ }
+}
+
+
+