initial commit of skywalking-rust with full-tracing features. (#5)
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..8993576
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+target/
+e2e/target
\ No newline at end of file
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 2cfeb06..a937273 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -11,19 +11,14 @@
jobs:
CI:
- runs-on: ubuntu-18.04
- timeout-minutes: 180
- strategy:
- fail-fast: true
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
- with:
- submodules: true
- - uses: actions-rs/cargo@v1
- with:
- command: build
- args: --release --all-features
- - name: 'Install & Test'
+ - uses: actions/checkout@v2
+ - name: install Rust
run: |
- cargo build
- cargo test
\ No newline at end of file
+ git submodule update --init --recursive
+ rustup toolchain install stable --component clippy --component rustfmt
+ - name: Format
+ run: cargo fmt -- --check
+ - name: clippy
+ run: cargo clippy
diff --git a/.gitignore b/.gitignore
index 07827cc..11469bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
-target/
-.idea/
\ No newline at end of file
+/target
+/tests/e2e/target
+.idea/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..69d308e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "skywalking-data-collect-protocol"]
+ path = skywalking-data-collect-protocol
+ url = https://github.com/apache/skywalking-data-collect-protocol.git
diff --git a/Cargo.lock b/Cargo.lock
index e99ac24..e38a696 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,31 +1,136 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
-name = "base64"
-version = "0.11.0"
+name = "anyhow"
+version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
+checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
[[package]]
-name = "c2-chacha"
-version = "0.2.3"
+name = "async-stream"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
+checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625"
dependencies = [
- "ppv-lite86",
+ "async-stream-impl",
+ "futures-core",
]
[[package]]
-name = "cfg-if"
-version = "0.1.10"
+name = "async-stream-impl"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bytes"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "fixedbitset"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "futures-channel"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
+
+[[package]]
+name = "futures-task"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
+
+[[package]]
+name = "futures-util"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
+dependencies = [
+ "autocfg",
+ "futures-core",
+ "futures-task",
+ "pin-project-lite",
+ "pin-utils",
+]
[[package]]
name = "getrandom"
-version = "0.1.14"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
@@ -33,6 +138,153 @@
]
[[package]]
+name = "h2"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "http"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
+
+[[package]]
+name = "httpdate"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
+
+[[package]]
+name = "hyper"
+version = "0.14.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-timeout"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
+dependencies = [
+ "hyper",
+ "pin-project-lite",
+ "tokio",
+ "tokio-io-timeout",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -40,23 +292,241 @@
[[package]]
name = "libc"
-version = "0.2.67"
+version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
+checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
+
+[[package]]
+name = "lock_api"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "mio"
+version = "0.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
+dependencies = [
+ "libc",
+ "log",
+ "miow",
+ "ntapi",
+ "winapi",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "multimap"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
+
+[[package]]
+name = "ntapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
+
+[[package]]
+name = "parking_lot"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
+dependencies = [
+ "cfg-if",
+ "instant",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "winapi",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+
+[[package]]
+name = "petgraph"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
-version = "0.2.6"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
+checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "prost"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020"
+dependencies = [
+ "bytes",
+ "prost-derive",
+]
+
+[[package]]
+name = "prost-build"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
+dependencies = [
+ "bytes",
+ "heck",
+ "itertools",
+ "log",
+ "multimap",
+ "petgraph",
+ "prost",
+ "prost-types",
+ "tempfile",
+ "which",
+]
+
+[[package]]
+name = "prost-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba"
+dependencies = [
+ "anyhow",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "prost-types"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b"
+dependencies = [
+ "bytes",
+ "prost",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
+dependencies = [
+ "proc-macro2",
+]
[[package]]
name = "rand"
-version = "0.7.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
- "getrandom",
"libc",
"rand_chacha",
"rand_core",
@@ -65,43 +535,390 @@
[[package]]
name = "rand_chacha"
-version = "0.2.1"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
- "c2-chacha",
+ "ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
-version = "0.5.1"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
-version = "0.2.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [
"rand_core",
]
[[package]]
-name = "skywalking-core"
-version = "0.1.0"
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "serde"
+version = "1.0.132"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "skywalking_rust"
+version = "0.0.1"
+dependencies = [
+ "async-stream",
"base64",
- "lazy_static",
+ "bytes",
+ "prost",
+ "prost-derive",
+ "tokio",
+ "tonic",
+ "tonic-build",
+ "uuid",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
+
+[[package]]
+name = "smallvec"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
+
+[[package]]
+name = "socket2"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc",
"rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "tokio"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
+dependencies = [
+ "bytes",
+ "libc",
+ "memchr",
+ "mio",
+ "num_cpus",
+ "once_cell",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "tokio-macros",
+ "winapi",
+]
+
+[[package]]
+name = "tokio-io-timeout"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90c49f106be240de154571dd31fbe48acb10ba6c6dd6f6517ad603abffa42de9"
+dependencies = [
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tonic"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "796c5e1cd49905e65dd8e700d4cb1dffcbfdb4fc9d017de08c1a537afd83627c"
+dependencies = [
+ "async-stream",
+ "async-trait",
+ "base64",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-timeout",
+ "percent-encoding",
+ "pin-project",
+ "prost",
+ "prost-derive",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+ "tracing-futures",
+]
+
+[[package]]
+name = "tonic-build"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12b52d07035516c2b74337d2ac7746075e7dcae7643816c1b12c5ff8a7484c08"
+dependencies = [
+ "proc-macro2",
+ "prost-build",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tower"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5651b5f6860a99bd1adb59dbfe1db8beb433e73709d9032b413a77e2fb7c066a"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "indexmap",
+ "pin-project",
+ "pin-project-lite",
+ "rand",
+ "slab",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62"
+
+[[package]]
+name = "tower-service"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+
+[[package]]
+name = "tracing"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
+dependencies = [
+ "cfg-if",
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "tracing-futures"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
+dependencies = [
+ "pin-project",
+ "tracing",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom",
+ "serde",
+]
+
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
]
[[package]]
name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
+version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "which"
+version = "4.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
+dependencies = [
+ "either",
+ "lazy_static",
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
index 629476f..f1634bc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,8 +13,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-[workspace]
+[package]
+name = "skywalking_rust"
+version = "0.0.1"
+authors = ["Rei Shimizu (Shikugawa@gmail.com)"]
+edition = "2018"
-members = [
- "core",
-]
\ No newline at end of file
+[dependencies]
+tonic = "0.5.2"
+bytes = "1.1.0"
+prost = "0.8.0"
+prost-derive = "0.8.0"
+uuid = { version = "0.8", features = ["serde", "v4"] }
+base64 = "0.13.0"
+tokio = { version = "1", features = ["full"] }
+async-stream = "0.3.2"
+
+[build-dependencies]
+tonic-build = "0.5.2"
+
+[[example]]
+name = "simple_trace_report"
+path = "examples/simple_trace_report.rs"
diff --git a/README.md b/README.md
index f9ca49d..ac106cd 100644
--- a/README.md
+++ b/README.md
@@ -30,60 +30,43 @@
TracingContext is the context of the tracing process. Span should only be created through context, and be archived into the
context after the span finished.
-## Injectable
-Injectable is used(optional) when the exit span creates. This Injectable received the notification from tracing context,
-including the key and value for tracing context across process propagation. Typically, Injectable implementation would
-manipulate the RPC header/metadata to make the key/value sent to the server side.
-
-## Extractable
-Extractable is used(optional) when the entry span creates. The Extractable fetches the value of the given key from the propagated
-context. Typically, Extractable implementation would read the RPC header/metadata, which sent from the client side.
-
-# APIs
-## High-Level APIs
-High level APIs are targeting convenient usages. These APIs use the ThreadLocal to propagate the context, so users could
-create span at any moment, and the context will finish automatically once the first created span of this thread stopped.
+# Example
```rust
-ContextManager::tracing_entry("op1", Some(&injector), |mut span| {
- // Use span freely in this closure
- // Span's start/end time is set automatically with this closure start/end(s).
- span.tag(Tag::new(String::from("tag1"), String::from("value1")));
+use skywalking_rust::context::trace_context::TracingContext;
+use skywalking_rust::reporter::grpc::Reporter;
+use tokio;
- ContextManager::tracing_exit("op2", "127.0.0.1:8080", Some(&extractor), |mut span| {
- span.set_component_id(33);
- });
-
- ContextManager::tracing_local("op3", |mut span| {});
-});
-```
-
-## Low-Level Core APIs
-Tracing core APIs are 100% manual control tracing APIs. Users could use them to trace any process by following SkyWalking
-core concepts.
-
-Low Level APIs request users to create and hold the context and span by the codes manually.
-
-```rust
-let mut context = TracingContext::new(reporter.service_instance_id()).unwrap();
-let span1 = context.create_entry_span("op1", None, Some(&dyn injector));
-{
- assert_eq!(span1.span_id(), 0);
- let mut span2 = context.create_local_span("op2", Some(&span1));
- span2.tag(Tag::new(String::from("tag1"), String::from("value1")));
+async fn handle_request(reporter: ContextReporter) {
+ let mut ctx = TracingContext::default("svc", "ins");
{
- assert_eq!(span2.span_id(), 1);
- let mut span3 = context.create_exit_span("op3", Some(&span2), "127.0.0.1:8080", Some(&dyn extractor));
- assert_eq!(span3.span_id(), 2);
+ // Generate an Entry Span when a request
+ // is received. An Entry Span is generated only once per context.
+ let span = ctx.create_entry_span("operation1").unwrap();
- context.finish_span(span3);
+ // Something...
+
+ {
+ // Generates an Exit Span when executing an RPC.
+ let span2 = ctx.create_exit_span("operation2").unwrap();
+
+ // Something...
+
+ ctx.finalize_span(span2);
+ }
+
+ ctx.finalize_span(span);
}
- context.finish_span(span2);
+ reporter.send(context).await;
}
-context.finish_span(span1);
-reporter.report_trace(context);
+#[tokio::main]
+async fn main() {
+ let tx = Reporter::start("http://0.0.0.0:11800".to_string()).await;
+
+ // Start server...
+}
```
# License
-Apache 2.0
\ No newline at end of file
+Apache 2.0
diff --git a/core/src/lib.rs b/build.rs
similarity index 71%
copy from core/src/lib.rs
copy to build.rs
index f94e272..157d3d4 100644
--- a/core/src/lib.rs
+++ b/build.rs
@@ -5,13 +5,19 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
-
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ tonic_build::configure().compile(
+ &["./skywalking-data-collect-protocol/language-agent/Tracing.proto"],
+ &["./skywalking-data-collect-protocol"],
+ )?;
+ Ok(())
+}
diff --git a/core/Cargo.toml b/core/Cargo.toml
deleted file mode 100644
index c187379..0000000
--- a/core/Cargo.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http:#www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-[package]
-name = "skywalking-core"
-version = "0.1.0"
-authors = ["Apache Software Foundation (ASF)"]
-edition = "2018"
-description = "SkyWalking tracing core APIs. Provide the way to build SkyWalking native format traces/spans and propagated context."
-license = "Apache 2.0"
-
-[dependencies]
-rand = "0.7.3"
-base64 = "0.11.0"
-lazy_static = "1.4.0"
\ No newline at end of file
diff --git a/core/src/skywalking/agent/context_manager.rs b/core/src/skywalking/agent/context_manager.rs
deleted file mode 100644
index 5c5df7f..0000000
--- a/core/src/skywalking/agent/context_manager.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use std::borrow::{Borrow, BorrowMut};
-use std::cell::RefCell;
-use std::rc::Rc;
-
-use lazy_static::lazy_static;
-
-use crate::skywalking::agent::reporter::Reporter;
-use crate::skywalking::core::{Context, ContextListener, Extractable, Injectable, Span, TracingContext};
-use crate::skywalking::core::span::TracingSpan;
-
-/// Thread Local tracing context. Host the context and propagate it in each thread if needed.
-thread_local!( static CTX: RefCell<CurrentTracingContext> = RefCell::new(CurrentTracingContext::new()));
-/// Global reporter
-/// Status: WIP
-lazy_static! {
- static ref SKYWALKING_REPORTER : Reporter = {
- Reporter::new()
- };
-}
-
-pub struct ContextManager {}
-
-impl ContextManager {
- /// Run a closure under an entry span observing.
- /// Span is automatically created, started and ended around the closure f.
- pub fn tracing_entry<F>(operation_name: &str, extractor: Option<&dyn Extractable>, f: F)
- where F: FnOnce(&mut Box<dyn Span>) {
- CTX.with(|context| {
- let span;
- {
- // Borrow mut ref has to end in this specific scope, as the context is nested used in f<F>
- let mut mut_context = context.borrow_mut();
- let parent_span_id = mut_context.parent_span_id();
- span = mut_context.create_entry_span(operation_name, parent_span_id, extractor);
- }
- match span {
- None => {}
- Some(mut s) => {
- s.start();
- f(s.borrow_mut());
- s.end();
-
- let is_first_span = s.span_id() == 0;
- let mut mut_context = context.borrow_mut();
- mut_context.finish_span(s);
-
- if is_first_span {
- mut_context.finish();
- }
- }
- };
- });
- }
-
- /// Run a closure under an exit span observing.
- /// Span is automatically created, started and ended around the closure f.
- pub fn tracing_exit<F>(operation_name: &str, peer: &str, injector: Option<&dyn Injectable>, f: F)
- where F: FnOnce(&mut Box<dyn Span>) {
- CTX.with(|context| {
- let span;
- {
- // Borrow mut ref has to end in this specific scope, as the context is nested used in f<F>
- let mut mut_context = context.borrow_mut();
- let parent_span_id = mut_context.parent_span_id();
- span = mut_context.create_exit_span(operation_name, parent_span_id, peer, injector);
- }
- match span {
- None => {}
- Some(mut s) => {
- s.start();
- f(s.borrow_mut());
- s.end();
-
- let is_first_span = s.span_id() == 0;
-
- let mut mut_context = context.borrow_mut();
- mut_context.finish_span(s);
-
- if is_first_span {
- mut_context.finish();
- }
- }
- };
- });
- }
-
- /// Run a closure under a local span observing.
- /// Span is automatically created, started and ended around the closure f.
- pub fn tracing_local<F>(operation_name: &str, f: F)
- where F: FnOnce(&mut Box<dyn Span>) {
- CTX.with(|context| {
- let span;
- {
- // Borrow mut ref has to end in this specific scope, as the context is nested used in f<F>
- let mut mut_context = context.borrow_mut();
- let parent_span_id = mut_context.parent_span_id();
- span = mut_context.create_local(operation_name, parent_span_id);
- }
- match span {
- None => {}
- Some(mut s) => {
- s.start();
- f(s.borrow_mut());
- s.end();
-
- let is_first_span = s.span_id() == 0;
-
- let mut mut_context = context.borrow_mut();
- mut_context.finish_span(s);
-
- if is_first_span {
- mut_context.finish();
- }
- }
- };
- });
- }
-}
-
-struct CurrentTracingContext {
- option: Option<Box<WorkingContext>>,
-}
-
-struct WorkingContext {
- context: Box<TracingContext>,
- span_stack: Vec<i32>,
-}
-
-impl CurrentTracingContext {
- /// Create the tracing context in the thread local at the first time.
- fn new() -> Self {
- CurrentTracingContext {
- option: match TracingContext::new(SKYWALKING_REPORTER.service_instance_id()) {
- Some(tx) => {
- Some(Box::new(WorkingContext {
- context: Box::new(tx),
- span_stack: Vec::new(),
- }))
- }
- None => { None }
- },
- }
- }
-
- /// Delegate to the tracing core entry span creation method, if current context is valid.
- fn create_entry_span(&mut self, operation_name: &str, parent_span_id: Option<i32>, extractor: Option<&dyn Extractable>) -> Option<Box<dyn Span>> {
- match self.option.borrow_mut() {
- None => { None }
- Some(wx) => {
- let span = wx.context.create_entry_span(operation_name, parent_span_id, extractor);
- wx.span_stack.push(span.span_id());
- Some(span)
- }
- }
- }
-
- /// Delegate to the tracing core exit span creation method, if current context is valid.
- fn create_exit_span(&mut self, operation_name: &str, parent_span_id: Option<i32>, peer: &str, injector: Option<&dyn Injectable>) -> Option<Box<dyn Span>> {
- match self.option.borrow_mut() {
- None => { None }
- Some(wx) => {
- let span = wx.context.create_exit_span(operation_name, parent_span_id, peer, injector);
- wx.span_stack.push(span.span_id());
- Some(span)
- }
- }
- }
-
- /// Delegate to the tracing core local span creation method, if current context is valid.
- fn create_local(&mut self, operation_name: &str, parent_span_id: Option<i32>) -> Option<Box<dyn Span>> {
- match self.option.borrow_mut() {
- None => { None }
- Some(wx) => {
- let span = wx.context.create_local_span(operation_name, parent_span_id);
- wx.span_stack.push(span.span_id());
- Some(span)
- }
- }
- }
-
- /// Delegate to the tracing core span finish method, if current context is valid.
- fn finish_span(&mut self, span: Box<dyn Span>) {
- match self.option.borrow_mut() {
- None => {}
- Some(wx) => {
- wx.context.finish_span(span);
- wx.span_stack.pop();
- }
- };
- }
-
- /// Fetch the parent span id, to be used in next new span.
- /// The span id(s) are saved in the span_stack by following as same the stack-style as span creation sequence.
- fn parent_span_id(&self) -> Option<i32> {
- match self.option.borrow() {
- None => { None }
- Some(wx) => {
- match wx.span_stack.last() {
- None => { None }
- Some(span_id) => { Some(span_id.clone()) }
- }
- }
- }
- }
-
- /// Finish the current tracing context, including
- /// 1. Clear up the context
- /// 2. Transfer the context to profobuf format and pass to reporter.
- fn finish(&mut self) {
- match self.option.borrow_mut() {
- None => {}
- Some(wx) => {
- let tracingContext = &wx.context;
-
- wx.span_stack.clear();
-
- // TODO: Transfer tracingContext to protobuf
- }
- }
- self.option = None;
- }
-}
-
-
-#[cfg(test)]
-mod context_tests {
- use crate::skywalking::agent::context_manager::*;
- use crate::skywalking::core::{ContextListener, Tag, TracingContext};
-
- #[test]
- fn test_context_manager() {
- ContextManager::tracing_entry("op1", None, |mut span| {
- span.tag(Tag::new(String::from("tag1"), String::from("value1")));
-
- ContextManager::tracing_exit("op2", "127.0.0.1:8080", None, |mut span| {
- span.set_component_id(33);
- });
-
- ContextManager::tracing_local("op3", |mut span| {});
- });
- }
-
- struct MockReporter {}
-
- impl ContextListener for MockReporter {
- fn service_instance_id(&self) -> Option<i32> {
- Some(1)
- }
-
- fn report_trace(&self, finished_context: Box<TracingContext>) {}
- }
-}
diff --git a/core/src/skywalking/agent/reporter.rs b/core/src/skywalking/agent/reporter.rs
deleted file mode 100644
index cf26f3f..0000000
--- a/core/src/skywalking/agent/reporter.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::skywalking::core::{ContextListener, TracingContext};
-
-pub struct Reporter {}
-
-impl ContextListener for Reporter {
- fn service_instance_id(&self) -> Option<i32> {
- Some(1)
- }
-
- fn report_trace(&self, finished_context: Box<TracingContext>) {
- unimplemented!()
- }
-}
-
-impl Reporter {
- pub fn new() -> Self {
- Reporter {}
- }
-}
\ No newline at end of file
diff --git a/core/src/skywalking/core/context.rs b/core/src/skywalking/core/context.rs
deleted file mode 100644
index a9465b3..0000000
--- a/core/src/skywalking/core/context.rs
+++ /dev/null
@@ -1,238 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use base64::{decode, encode};
-
-use crate::skywalking::agent::reporter::Reporter;
-use crate::skywalking::core::{ID, Span};
-use crate::skywalking::core::context_carrier::{Extractable, Injectable};
-use crate::skywalking::core::id::IDGenerator;
-use crate::skywalking::core::segment_ref::SegmentRef;
-use crate::skywalking::core::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 {
- /// Create an entry span belonging this context
- fn create_entry_span(&mut self, operation_name: &str, parent_span_id: Option<i32>, extractor: Option<&dyn Extractable>) -> Box<dyn Span>;
- /// Create an exit span belonging this context
- fn create_exit_span(&mut self, operation_name: &str, parent_span_id: Option<i32>, peer: &str, injector: Option<&dyn Injectable>) -> Box<dyn Span>;
- /// Create an local span belonging this context
- fn create_local_span(&mut self, operation_name: &str, parent_span_id: Option<i32>) -> Box<dyn Span>;
- /// Finish the given span. The span is only being accept if it belongs to this context.
- /// Return err if the span was created by another context.
- fn finish_span(&mut self, span: Box<dyn Span>);
-}
-
-pub struct TracingContext {
- /// Span id sequence. Indicate the number of created spans.
- next_seq: i32,
-
- primary_trace_id: ID,
- segment_id: ID,
- self_generated_id: bool,
- entry_endpoint_name: Option<String>,
- first_ref: Option<SegmentRef>,
- service_instance_id: i32,
-
- finished_spans: Vec<Box<dyn Span>>,
-}
-
-impl TracingContext {
- /// Create a new instance
- pub fn new(service_instance_id: Option<i32>) -> Option<TracingContext> {
- match service_instance_id {
- None => { None }
- Some(id) => {
- Some(TracingContext {
- next_seq: -1,
- primary_trace_id: IDGenerator::new_id(id),
- segment_id: IDGenerator::new_id(id),
- self_generated_id: true,
- entry_endpoint_name: None,
- first_ref: None,
- service_instance_id: id,
- finished_spans: Vec::new(),
- }
- )
- }
- }
- }
-
- pub fn service_instance_id(&self) -> i32 {
- self.service_instance_id
- }
-
- pub fn first_ref(&self) -> &Option<SegmentRef> {
- &self.first_ref
- }
-
- pub fn entry_endpoint_name(&self) -> &Option<String> {
- &self.entry_endpoint_name
- }
-
- pub fn trace_id(&self) -> ID {
- self.primary_trace_id.clone()
- }
-
- pub fn segment_id(&self) -> ID {
- self.segment_id.clone()
- }
-
- /// Fetch the next id for new span
- fn next_span_id(&mut self) -> i32 {
- self.next_seq = self.next_seq + 1;
- self.next_seq
- }
-}
-
-/// Default implementation of Context
-impl Context for TracingContext {
- fn create_entry_span(&mut self, operation_name: &str, parent_span_id: Option<i32>, extractor: Option<&dyn Extractable>) -> Box<dyn Span> {
- let mut entry_span = TracingSpan::new_entry_span(operation_name, self.next_span_id(), match parent_span_id {
- None => { -1 }
- Some(s) => { s }
- });
-
- if extractor.is_some() {
- match SegmentRef::from_text(extractor.unwrap().extract("sw6".to_string())) {
- Some(reference) => {
- if self.self_generated_id {
- self.self_generated_id = false;
- self.primary_trace_id = reference.get_trace_id();
- }
- if self.first_ref.is_none() {
- self.first_ref = Some(reference.clone());
- self.entry_endpoint_name = Some(String::from(operation_name))
- }
- entry_span._add_ref(reference);
- }
- _ => {}
- }
- }
- Box::new(entry_span)
- }
-
- fn create_exit_span(&mut self, operation_name: &str, parent_span_id: Option<i32>, peer: &str, injector: Option<&dyn Injectable>) -> Box<dyn Span> {
- let exit_span = TracingSpan::new_exit_span(operation_name, self.next_span_id(), match parent_span_id {
- None => { -1 }
- Some(s) => { s }
- }, peer);
-
- if injector.is_some() {
- injector.unwrap().inject(String::from("sw6"), SegmentRef::for_across_process(self, &exit_span, &peer).serialize());
- }
-
- Box::new(exit_span)
- }
-
- fn create_local_span(&mut self, operation_name: &str, parent_span_id: Option<i32>) -> Box<dyn Span> {
- Box::new(TracingSpan::new_local_span(operation_name, self.next_span_id(), match parent_span_id {
- None => { -1 }
- Some(s) => { s }
- }))
- }
-
- fn finish_span(&mut self, mut span: Box<dyn Span>) {
- if !span.is_ended() {
- span.end();
- }
- self.finished_spans.push(span);
- }
-}
-
-#[cfg(test)]
-mod context_tests {
- use std::sync::mpsc;
- use std::sync::mpsc::{Receiver, Sender};
-
- use crate::skywalking::core::{Context, ContextListener, Extractable, ID, Injectable, Tag, TracingContext};
-
- #[test]
- fn test_context_stack() {
- let reporter = MockReporter::new();
- let mut context = TracingContext::new(reporter.service_instance_id()).unwrap();
- let span1 = context.create_entry_span("op1", None, Some(&MockerHeader {}));
- {
- assert_eq!(span1.span_id(), 0);
- let mut span2 = context.create_local_span("op2", Some(span1.span_id()));
- span2.tag(Tag::new(String::from("tag1"), String::from("value1")));
- {
- assert_eq!(span2.span_id(), 1);
- let span3 = context.create_exit_span("op3", Some(span2.span_id()), "127.0.0.1:8080", Some(&HeaderCarrier {}));
- assert_eq!(span3.span_id(), 2);
-
- context.finish_span(span3);
- }
- context.finish_span(span2);
- }
- context.finish_span(span1);
-
- reporter.report_trace(Box::new(context));
- // context has moved into reporter. Can't be used again.
-
- let received_context = reporter.recv.recv().unwrap();
- assert_eq!(received_context.primary_trace_id == ID::new(3, 4, 5), true);
- assert_eq!(received_context.finished_spans.len(), 3);
- }
-
- #[test]
- fn test_no_context() {
- let context = TracingContext::new(None);
- assert_eq!(context.is_none(), true);
- }
-
- struct MockReporter {
- sender: Box<Sender<Box<TracingContext>>>,
- recv: Box<Receiver<Box<TracingContext>>>,
- }
-
- impl MockReporter {
- fn new() -> Self {
- let (tx, rx) = mpsc::channel();
- MockReporter {
- sender: Box::new(tx),
- recv: Box::new(rx),
- }
- }
- }
-
- impl ContextListener for MockReporter {
- fn service_instance_id(&self) -> Option<i32> {
- Some(1)
- }
-
- fn report_trace(&self, finished_context: Box<TracingContext>) {
- self.sender.send(finished_context);
- }
- }
-
- struct MockerHeader {}
-
- impl Extractable for MockerHeader {
- fn extract(&self, key: String) -> &str {
- "1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz"
- }
- }
-
- struct HeaderCarrier {}
-
- impl Injectable for HeaderCarrier {
- fn inject(&self, key: String, value: String) {
- assert_eq!(key, "sw6");
- assert_eq!(value.len() > 0, true);
- }
- }
-}
\ No newline at end of file
diff --git a/core/src/skywalking/core/context_carrier.rs b/core/src/skywalking/core/context_carrier.rs
deleted file mode 100644
index 3ab607d..0000000
--- a/core/src/skywalking/core/context_carrier.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/// The Injectable implementation supports inject the give key/value for further propagation,
-/// Such as putting a key/value into the HTTP header.
-pub trait Injectable {
- /// Inject the given key/value into the implementation.
- /// The way of injection is determined by the implementation, no panic! should happens even injection fails.
- fn inject(&self, key: String, value: String);
-}
-
-/// The Extractable implementations extract propagated context out the implementation.
-/// Such as fetching the key/value from the HTTP header.
-pub trait Extractable {
- /// Fetch the value by the given key.
- fn extract(&self, key: String) -> &str;
-}
\ No newline at end of file
diff --git a/core/src/skywalking/core/context_listener.rs b/core/src/skywalking/core/context_listener.rs
deleted file mode 100644
index 9cb5842..0000000
--- a/core/src/skywalking/core/context_listener.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::skywalking::core::TracingContext;
-
-///Report bridge defines the traits for the skywalking-report
-
-/// Register implementation communicate with the SkyWalking OAP backend.
-/// It does metadata register, traces report, and runtime status report or interaction.
-pub trait ContextListener {
- /// Return the registered service id
- /// If haven't registered successfully, return None.
- fn service_instance_id(&self) -> Option<i32>;
-
- /// Move the finished and inactive context to the reporter.
- /// The reporter should use async way to transport the data to the backend through HTTP, gRPC or SkyWalking forwarder.
- fn report_trace(&self, finished_context: Box<TracingContext>);
-}
diff --git a/core/src/skywalking/core/id.rs b/core/src/skywalking/core/id.rs
deleted file mode 100644
index 384963a..0000000
--- a/core/src/skywalking/core/id.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use std::hash::Hash;
-use std::time::SystemTime;
-
-use rand::RngCore;
-
-pub struct IDGenerator {}
-
-impl IDGenerator {
- /// ID generated by 3 parts
- /// 1. Registered service instance id
- /// 2. thread local level random u64
- /// 3. Timestamp in ms
- pub fn new_id(instance_id: i32) -> ID {
- ID::new(
- instance_id as i64,
- rand::thread_rng().next_u64() as i64,
- SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).ok().unwrap().as_millis() as i64,
- )
- }
-}
-
-/// ID is used for trace id and segment id.
-/// It is combined by 3 i64 numbers, and could be formatted as `part1.part2.part3` string.
-#[derive(Clone, Hash)]
-pub struct ID {
- part1: i64,
- part2: i64,
- part3: i64,
-}
-
-impl ID {
- pub fn new(part1: i64, part2: i64, part3: i64) -> Self {
- ID {
- part1,
- part2,
- part3,
- }
- }
-
- /// Convert the literal string text back to ID object.
- /// Return Option::None if the text is not combined by 3 dot split i64 parts
- pub fn from(id_text: String) -> Result<Self, String> {
- let strings: Vec<&str> = id_text.split(".").collect();
- if strings.len() == 3 {
- let part1 = strings[0].parse::<i64>();
- if part1.is_err() { return Err("part 1 is not a i64".to_string()); }
- let part2 = strings[1].parse::<i64>();
- if part2.is_err() { return Err("part 2 is not a i64".to_string()); }
- let part3 = strings[2].parse::<i64>();
- if part3.is_err() { return Err("part 3 is not a i64".to_string()); }
- Ok(ID::new(part1.unwrap(), part2.unwrap(), part3.unwrap()))
- } else {
- Err("The ID is not combined by 3 parts.".to_string())
- }
- }
-}
-
-impl PartialEq for ID {
- fn eq(&self, other: &Self) -> bool {
- self.part1 == other.part1 && self.part2 == other.part2 && self.part3 == other.part3
- }
-}
-
-impl ToString for ID {
- fn to_string(&self) -> String {
- format!("{}.{}.{}", self.part1, self.part2, self.part3)
- }
-}
-
-
-#[cfg(test)]
-mod id_tests {
- use crate::skywalking::core::ID;
- use crate::skywalking::core::id::IDGenerator;
-
- #[test]
- fn test_id_generator() {
- let id = IDGenerator::new_id(1);
- assert_eq!(id.part1, 1);
- }
-
- #[test]
- fn test_id_new() {
- let id1 = ID::new(1, 2, 3);
- let id2 = ID::new(1, 2, 3);
- let id3 = ID::new(1, 2, 4);
-
- assert_eq!(id1.eq(&id2), true);
- assert_eq!(id1.ne(&id3), true);
- assert_eq!(id1.to_string(), "1.2.3");
-
- let id4 = ID::from(String::from("1.2.3")).unwrap();
- assert_eq!(id4.eq(&id1), true);
-
- let id5_none = ID::from(String::from("1.2"));
- assert_ne!(id5_none.err().unwrap().len(), 0);
-
- let id6_illegal = ID::from(String::from("1.2.a"));
- assert_ne!(id6_illegal.err().unwrap().len(), 0);
- }
-}
\ No newline at end of file
diff --git a/core/src/skywalking/core/log.rs b/core/src/skywalking/core/log.rs
deleted file mode 100644
index e0b81f1..0000000
--- a/core/src/skywalking/core/log.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/// Log represents an event happened during the span duration.
-/// It is much heavier than tag. Usually this is only used in the error case to log the detailed error message.
-/// Log Entity is a creation once object. Can't be change once it is created.
-pub struct LogEvent {
- timestamp: i64,
- /// Any extra fields to describe the event.
- fields: Box<[EventField]>,
-}
-
-pub struct EventField {
- name: String,
- value: String,
-}
-
-impl LogEvent {
- pub fn new(timestamp: i64, fields: Box<[EventField]>) -> Self {
- LogEvent {
- timestamp,
- fields,
- }
- }
-}
-
-impl EventField {
- pub fn new(name: String, value: String) -> Self {
- EventField {
- name,
- value,
- }
- }
-}
-
-#[cfg(test)]
-mod log_tests {
- use crate::skywalking::core::log::{EventField, LogEvent};
-
- #[test]
- fn test_log_new() {
- let fields = [
- { EventField::new(String::from("event1"), String::from("event description")) },
- { EventField::new(String::from("event2"), String::from("event description")) },
- ];
- let event = LogEvent::new(123, Box::new(fields));
- assert_eq!(event.timestamp, 123);
- assert_eq!(event.fields.len(), 2);
- assert_eq!(event.fields[0].name, "event1");
- assert_eq!(event.fields[1].value, "event description");
- }
-}
-
diff --git a/core/src/skywalking/core/mod.rs b/core/src/skywalking/core/mod.rs
deleted file mode 100644
index 7715556..0000000
--- a/core/src/skywalking/core/mod.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-pub use context::Context;
-pub use context::TracingContext;
-pub use context_carrier::Extractable;
-pub use context_carrier::Injectable;
-pub use context_listener::ContextListener;
-pub use id::ID;
-pub use log::EventField;
-pub use log::LogEvent;
-pub use span::Span;
-pub use tag::Tag;
-
-pub mod span;
-pub mod context;
-pub mod tag;
-pub mod id;
-pub mod context_listener;
-pub mod log;
-pub mod context_carrier;
-pub mod segment_ref;
\ No newline at end of file
diff --git a/core/src/skywalking/core/segment_ref.rs b/core/src/skywalking/core/segment_ref.rs
deleted file mode 100644
index 421da20..0000000
--- a/core/src/skywalking/core/segment_ref.rs
+++ /dev/null
@@ -1,248 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use std::os::raw::c_long;
-
-use crate::skywalking::core::{ID, Span, TracingContext};
-use crate::skywalking::core::segment_ref::SegmentRefType::CROSS_PROCESS;
-
-#[derive(Clone, Hash)]
-pub struct SegmentRef {
- ref_type: SegmentRefType,
- trace_id: ID,
- segment_id: ID,
- span_id: i32,
- parent_service_instance_id: i32,
- entry_service_instance_id: i32,
- network_address: Option<String>,
- network_address_id: i32,
- entry_endpoint: Option<String>,
- entry_endpoint_id: i32,
- parent_endpoint: Option<String>,
- parent_endpoint_id: i32,
-}
-
-#[derive(Clone, Hash)]
-enum SegmentRefType {
- CROSS_PROCESS,
- CROSS_THREAD,
-}
-
-impl SegmentRef {
- pub fn from_text(value: &str) -> Option<Self> {
- let strings: Vec<&str> = value.split("-").collect();
- if strings.len() == 9 {
- // Ignore string[0].
- let trace_id = match SegmentRef::string_to_id(strings[1]) {
- Some(id) => { id }
- _ => { return None; }
- };
- let segment_id = match SegmentRef::string_to_id(strings[2]) {
- Some(id) => { id }
- _ => { return None; }
- };
- let span_id = match strings[3].parse::<i32>() {
- Ok(id) => { id }
- _ => { return None; }
- };
- let parent_service_instance_id = match strings[4].parse::<i32>() {
- Ok(id) => { id }
- _ => { return None; }
- };
- let entry_service_instance_id = match strings[5].parse::<i32>() {
- Ok(id) => { id }
- _ => { return None; }
- };
-
- let (network_address, network_address_id) = match SegmentRef::decode_base64_to_string_or_id(strings[6]) {
- Some(decoded) => { decoded }
- _ => { return None; }
- };
- let (entry_endpoint, entry_endpoint_id) = match SegmentRef::decode_base64_to_string_or_id(strings[7]) {
- Some(decoded) => { decoded }
- _ => { return None; }
- };
- let (parent_endpoint, parent_endpoint_id) = match SegmentRef::decode_base64_to_string_or_id(strings[8]) {
- Some(decoded) => { decoded }
- _ => { return None; }
- };
-
- Some(SegmentRef {
- ref_type: CROSS_PROCESS,
- trace_id,
- segment_id,
- span_id,
- parent_service_instance_id,
- entry_service_instance_id,
- network_address,
- network_address_id,
- entry_endpoint,
- entry_endpoint_id,
- parent_endpoint,
- parent_endpoint_id,
- })
- } else {
- None
- }
- }
-
- pub fn for_across_process(context: &TracingContext, exit_span: &dyn Span, peer: &str) -> Self {
- // -1 represent the object doesn't exist.
- let inexistence = -1;
- let (entry_endpoint, entry_endpoint_id) = match context.first_ref() {
- None => {
- match context.entry_endpoint_name() {
- None => { (None, inexistence) }
- Some(endpoint) => { (Some(endpoint.clone()), 0) }
- }
- }
- Some(reference) => {
- match &reference.entry_endpoint {
- None => { (None, reference.entry_endpoint_id) }
- Some(endpoint) => { (Some(endpoint.clone()), 0) }
- }
- }
- };
- let (parent_endpoint, parent_endpoint_id) = match context.entry_endpoint_name() {
- None => { (None, inexistence) }
- Some(endpoint) => { (Some(endpoint.clone()), 0) }
- };
-
- SegmentRef {
- ref_type: CROSS_PROCESS,
- trace_id: context.trace_id(),
- segment_id: context.segment_id(),
- span_id: exit_span.span_id(),
- network_address: Some(String::from(peer.clone())),
- // No network address register, the id always be 0
- network_address_id: 0,
- entry_service_instance_id: {
- match context.first_ref() {
- None => { context.service_instance_id() }
- Some(reference) => { reference.entry_service_instance_id }
- }
- },
- parent_service_instance_id: context.service_instance_id(),
- entry_endpoint,
- entry_endpoint_id,
- parent_endpoint,
- parent_endpoint_id,
- }
- }
-
- pub fn serialize(&self) -> String {
- let parts: Vec<String> = vec![
- "1".to_string(),
- base64::encode(self.trace_id.to_string().as_bytes()),
- base64::encode(self.segment_id.to_string().as_bytes()),
- self.span_id.to_string(),
- self.parent_service_instance_id.to_string(),
- self.entry_service_instance_id.to_string(),
- SegmentRef::string_or_id_to_encode_base64(&self.network_address, self.network_address_id),
- SegmentRef::string_or_id_to_encode_base64(&self.entry_endpoint, self.entry_endpoint_id),
- SegmentRef::string_or_id_to_encode_base64(&self.parent_endpoint, self.parent_endpoint_id),
- ];
- parts.join("-")
- }
-
- pub fn get_trace_id(&self) -> ID {
- self.trace_id.clone()
- }
-
- fn string_to_id(text: &str) -> Option<ID> {
- match base64::decode(text) {
- Ok(value) => {
- match String::from_utf8(value) {
- Ok(str) => {
- match ID::from(str) {
- Ok(id) => { Some(id) }
- _ => None
- }
- }
- _ => { None }
- }
- }
- _ => { None }
- }
- }
-
- fn decode_base64_to_string_or_id(text: &str) -> Option<(Option<String>, i32)> {
- match base64::decode(text) {
- Ok(value) => {
- match String::from_utf8(value) {
- Ok(str) => {
- if str.starts_with("#") {
- let network: Vec<&str> = str.split("#").collect();
- (Some((Some(network[1].to_string()), 0)))
- } else {
- match str.parse::<i32>() {
- Ok(id) => { Some((None, id)) }
- _ => { None }
- }
- }
- }
- _ => { None }
- }
- }
- _ => { None }
- }
- }
-
- fn string_or_id_to_encode_base64(text: &Option<String>, id: i32) -> String {
- base64::encode(match text {
- None => { id.to_string() }
- Some(t) => {
- let mut network = "#".to_string();
- network.push_str(&t);
- network
- }
- }.as_bytes())
- }
-}
-
-#[cfg(test)]
-mod segment_ref_tests {
- use crate::skywalking::core::ID;
- use crate::skywalking::core::segment_ref::SegmentRef;
-
- #[test]
- fn test_deserialize_context_carrier() {
- let carrier = SegmentRef::from_text("1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz").unwrap();
- assert_eq!(carrier.trace_id == ID::new(3, 4, 5), true);
- assert_eq!(carrier.segment_id == ID::new(1, 2, 3), true);
- assert_eq!(carrier.span_id, 4);
- assert_eq!(carrier.entry_service_instance_id, 1);
- assert_eq!(carrier.parent_service_instance_id, 1);
- assert_eq!(carrier.network_address, Some("127.0.0.1:8080".to_string()));
- assert_eq!(carrier.entry_endpoint, Some("/portal".to_string()));
- assert_eq!(carrier.parent_endpoint_id, 123);
- }
-
- #[test]
- fn test_serialize_ref() {
- let carrier = SegmentRef::from_text("1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz").unwrap();
- assert_eq!(carrier.trace_id == ID::new(3, 4, 5), true);
- assert_eq!(carrier.segment_id == ID::new(1, 2, 3), true);
- assert_eq!(carrier.span_id, 4);
- assert_eq!(carrier.entry_service_instance_id, 1);
- assert_eq!(carrier.parent_service_instance_id, 1);
- assert_eq!(carrier.network_address, Some("127.0.0.1:8080".to_string()));
- assert_eq!(carrier.entry_endpoint, Some("/portal".to_string()));
- assert_eq!(carrier.parent_endpoint_id, 123);
-
- let carrier_text = carrier.serialize();
- assert_eq!(carrier_text, "1-My40LjU=-MS4yLjM=-4-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWw=-MTIz");
- }
-}
diff --git a/core/src/skywalking/core/span.rs b/core/src/skywalking/core/span.rs
deleted file mode 100644
index 9842dea..0000000
--- a/core/src/skywalking/core/span.rs
+++ /dev/null
@@ -1,264 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use std::time::SystemTime;
-
-use crate::skywalking::core::log::LogEvent;
-use crate::skywalking::core::segment_ref::SegmentRef;
-use crate::skywalking::core::Tag;
-
-/// Span is one of the tracing concept, representing a time duration.
-///Span is an important and common concept in distributed tracing system. Learn Span from Google Dapper Paper.
-/// For better performance, we extend the span into 3 kinds.
-///
-/// 1. EntrySpan EntrySpan represents a service provider, also the endpoint of server side. As an APM system, we are targeting the application servers. So almost all the services and MQ-consumer are EntrySpan(s).
-/// 2. LocalSpan LocalSpan represents a normal Java method, which does not relate to remote service, neither a MQ producer/consumer nor a service(e.g. HTTP service) provider/consumer.
-/// 3. ExitSpan ExitSpan represents a client of service or MQ-producer, as named as LeafSpan at early age of SkyWalking. e.g. accessing DB by JDBC, reading Redis/Memcached are cataloged an ExitSpan.
-pub trait Span {
- /// Start the span with the current system time
- fn start(&mut self);
- /// Start the span by using given time point.
- fn start_with_timestamp(&mut self, timestamp: SystemTime);
- /// Add a new tag to the span
- fn tag(&mut self, tag: Tag);
- /// Add a log event to the span
- fn log(&mut self, log: LogEvent);
- /// Indicate error occurred during the span execution.
- fn error_occurred(&mut self);
- /// Set the component id represented by this span.
- /// Component id is pre-definition in the SkyWalking OAP backend component-libraries.yml file.
- /// Read [Component library settings](https://github.com/apache/skywalking/blob/master/docs/en/guides/Component-library-settings.md) documentation for more details
- fn set_component_id(&mut self, component_id: i32);
- /// End the span with the current system time.
- /// End just means sealing the end time, still need to call Context::finish_span to officially finish span and archive it for further reporting.
- fn end(&mut self);
- /// End the span by using given time point.
- /// End just means sealing the end time, still need to call Context::finish_span to officially finish span and archive it for further reporting.
- fn end_with_timestamp(&mut self, timestamp: SystemTime);
-
-
- /// All following are status reading methods.
-
- /// Return true if the span has been set end time
- fn is_ended(&self) -> bool;
- /// Return true if the span is an entry span
- fn is_entry(&self) -> bool;
- /// Return true if the span is an exit span
- fn is_exit(&self) -> bool;
- /// Return span id.
- fn span_id(&self) -> i32;
- /// Return the replicated existing tags.
- fn tags(&self) -> Vec<Tag>;
-}
-
-pub struct TracingSpan {
- /// The operation name represents the logic process of this span
- operation_name: String,
- span_id: i32,
- parent_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,
- /// The peer network address when as an RPC related span.
- /// Typically used in exit span, representing the target server address.
- peer: Option<String>,
- /// Tag this span in error status.
- error_occurred: bool,
- /// Component id is defined in the main repo to represent the library kind.
- component_id: Option<i32>,
- tags: Vec<Tag>,
- logs: Vec<LogEvent>,
- refs: Vec<SegmentRef>,
-}
-
-/// Tracing Span is only created inside TracingContext.
-impl TracingSpan {
- /// Create a new entry span
- pub fn new_entry_span(operation_name: &str, span_id: i32, parent_span_id: i32) -> TracingSpan {
- let mut span = TracingSpan::_new(operation_name, span_id, parent_span_id);
- span.is_entry = true;
- span
- }
-
- /// Create a new exit span
- pub fn new_exit_span(operation_name: &str, span_id: i32, parent_span_id: i32, peer: &str) -> TracingSpan {
- let mut span = TracingSpan::_new(operation_name, span_id, parent_span_id);
- span.is_exit = true;
- span.peer = Some(String::from(peer));
- span
- }
-
- /// Create a new local span
- pub fn new_local_span(operation_name: &str, span_id: i32, parent_span_id: i32) -> TracingSpan {
- let span = TracingSpan::_new(operation_name, span_id, parent_span_id);
- span
- }
-
- /// Create a span
- fn _new(operation_name: &str, span_id: i32, parent_span_id: i32) -> Self {
- TracingSpan {
- operation_name: String::from(operation_name),
- span_id,
- parent_span_id,
- start_time: 0,
- end_time: 0,
- is_entry: false,
- is_exit: false,
- peer: None,
- error_occurred: false,
- component_id: None,
- tags: Vec::new(),
- logs: Vec::new(),
- refs: Vec::new(),
- }
- }
-
- pub fn _add_ref(&mut self, reference: SegmentRef) {
- self.refs.push(reference);
- }
-}
-
-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 tag(&mut self, tag: Tag) {
- self.tags.push(tag);
- }
-
- fn log(&mut self, log: LogEvent) {
- self.logs.push(log);
- }
-
- fn error_occurred(&mut self) {
- self.error_occurred = true;
- }
-
- fn set_component_id(&mut self, component_id: i32) {
- self.component_id = Some(component_id);
- }
-
- fn end(&mut self) {
- self.end_time = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
- Ok(n) => { n.as_millis() }
- Err(_) => self.start_time as u128,
- } as u64;
- }
-
- fn end_with_timestamp(&mut self, timestamp: SystemTime) {
- self.end_time = match timestamp.duration_since(SystemTime::UNIX_EPOCH) {
- Ok(n) => { n.as_millis() }
- Err(_) => self.start_time as u128,
- } as u64;
- }
-
- fn is_ended(&self) -> bool {
- self.end_time != 0
- }
-
- fn is_entry(&self) -> bool {
- self.is_entry
- }
-
- fn is_exit(&self) -> bool {
- self.is_exit
- }
-
- fn span_id(&self) -> i32 {
- self.span_id
- }
-
- fn tags(&self) -> Vec<Tag> {
- let mut tags = Vec::new();
- for t in &self.tags {
- tags.push(t.clone());
- };
- tags
- }
-}
-
-#[cfg(test)]
-mod span_tests {
- use std::time::SystemTime;
-
- use crate::skywalking::core::log::{EventField, LogEvent};
- use crate::skywalking::core::span::*;
- use crate::skywalking::core::Tag;
-
- #[test]
- fn test_span_new() {
- let mut span = TracingSpan::_new("op1", 0, -1);
- assert_eq!(span.parent_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("op2", 1, 0);
- assert_eq!("op2", span2.operation_name);
- assert_eq!(span2.parent_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 span = TracingSpan::new_entry_span("op1", 0, 1);
- assert_eq!(span.is_entry(), true)
- }
-
- #[test]
- fn test_span_with_tags() {
- let mut span = TracingSpan::new_entry_span("op1", 0, 1);
- span.tag(Tag::new(String::from("tag1"), String::from("value1")));
- span.tag(Tag::new(String::from("tag2"), String::from("value2")));
-
- let tags = span.tags();
- assert_eq!(tags.len(), 2);
- assert_eq!(tags.get(0).unwrap().key(), "tag1")
- }
-
- #[test]
- fn test_span_with_logs() {
- let mut span = TracingSpan::_new("op1", 0, -1);
-
- span.log(LogEvent::new(123, Box::new([
- { EventField::new(String::from("event1"), String::from("event description")) },
- { EventField::new(String::from("event2"), String::from("event description")) },
- ])));
-
- assert_eq!(span.logs.len(), 1);
- }
-}
-
-
-
diff --git a/core/src/skywalking/core/tag.rs b/core/src/skywalking/core/tag.rs
deleted file mode 100644
index 80bbad9..0000000
--- a/core/src/skywalking/core/tag.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/// Tag is a key value pair to represent an supplementary instruction for the span.
-/// Common and most widely used tags could be found here,
-/// https://github.com/apache/skywalking/blob/master/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/tag/Tags.java.
-#[derive(Clone, Hash)]
-pub struct Tag {
- key: String,
- value: String,
-}
-
-impl Tag {
- pub fn new(key: String, value: String) -> Self {
- Tag {
- key,
- value,
- }
- }
-
- pub fn key(&self) -> String {
- self.key.clone()
- }
-
- pub fn value(&self) -> String {
- self.value.clone()
- }
-}
-
-#[cfg(test)]
-mod tag_tests {
- use crate::skywalking::core::Tag;
-
- #[test]
- fn test_tag_new() {
- let tag = Tag::new(String::from("tag_key"), String::from("tag_value"));
- assert_eq!(tag.key, "tag_key");
- assert_eq!(tag.value, "tag_value");
- let tag_clone = tag.clone();
- assert_eq!(tag_clone.key, "tag_key");
- assert_eq!(tag_clone.value, "tag_value");
- }
-}
\ No newline at end of file
diff --git a/core/src/skywalking/mod.rs b/core/src/skywalking/mod.rs
deleted file mode 100644
index 08730c9..0000000
--- a/core/src/skywalking/mod.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-pub mod core;
-pub mod agent;
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
new file mode 100644
index 0000000..579fc58
--- /dev/null
+++ b/docker-compose.dev.yml
@@ -0,0 +1,65 @@
+version: "3.7"
+services:
+ # Skywalking components.
+ elasticsearch:
+ image: elasticsearch:7.9.2
+ restart: always
+ ports:
+ - 9200:9200
+ healthcheck:
+ test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+ environment:
+ discovery.type: single-node
+ expose:
+ - "9200"
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ consul:
+ image: docker.io/bitnami/consul:1-debian-10
+ ports:
+ - '8300:8300'
+ - '8301:8301'
+ - '8301:8301/udp'
+ - '8500:8500'
+ - '8600:8600'
+ - '8600:8600/udp'
+ oap:
+ image: apache/skywalking-oap-server:8.6.0-es7
+ depends_on:
+ - elasticsearch
+ links:
+ - elasticsearch
+ ports:
+ - 11800:11800
+ - 12800:12800
+ environment:
+ SW_STORAGE: elasticsearch7
+ SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
+ restart: always
+ healthcheck:
+ test: ["CMD-SHELL", "/skywalking/bin/swctl"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+ depends_on:
+ - consul
+ - elasticsearch
+ ui:
+ image: apache/skywalking-ui:8.6.0
+ depends_on:
+ - oap
+ links:
+ - oap
+ ports:
+ - 8080:8080
+ environment:
+ SW_OAP_ADDRESS: oap:12800
+ depends_on:
+ - oap
\ No newline at end of file
diff --git a/docker-compose.e2e.yml b/docker-compose.e2e.yml
new file mode 100644
index 0000000..3c28ead
--- /dev/null
+++ b/docker-compose.e2e.yml
@@ -0,0 +1,30 @@
+version: "3.7"
+services:
+ collector:
+ build:
+ context: .
+ dockerfile: ./tests/e2e/docker/Dockerfile.tool
+ ports:
+ - 19876:19876
+ - 12800:12800
+
+ consumer:
+ build:
+ context: .
+ dockerfile: ./tests/e2e/docker/Dockerfile
+ expose:
+ - 8082
+ command: cargo run -- --mode consumer
+ depends_on:
+ - collector
+
+ producer:
+ build:
+ context: .
+ dockerfile: ./tests/e2e/docker/Dockerfile
+ ports:
+ - 8081:8081
+ command: cargo run -- --mode producer
+ depends_on:
+ - collector
+ - consumer
\ No newline at end of file
diff --git a/examples/simple_trace_report.rs b/examples/simple_trace_report.rs
new file mode 100644
index 0000000..6848475
--- /dev/null
+++ b/examples/simple_trace_report.rs
@@ -0,0 +1,16 @@
+use skywalking_rust::context::system_time::UnixTimeStampFetcher;
+use skywalking_rust::context::trace_context::TracingContext;
+use skywalking_rust::reporter::grpc::Reporter;
+use std::sync::Arc;
+use tokio;
+
+#[tokio::main]
+async fn main() {
+ let tx = Reporter::start("http://0.0.0.0:11800".to_string()).await;
+ let mut context = TracingContext::default_internal("service", "instance");
+ {
+ let span = context.create_entry_span("op1").unwrap();
+ context.finalize_span(span);
+ }
+ let _ = tx.send(context).await;
+}
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..a8774cb
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+PyYAML==5.4
+apache-skywalking==0.5.0
diff --git a/skywalking-data-collect-protocol b/skywalking-data-collect-protocol
new file mode 160000
index 0000000..fbbe955
--- /dev/null
+++ b/skywalking-data-collect-protocol
@@ -0,0 +1 @@
+Subproject commit fbbe955545fd2c942ca59cd05720a084d010bb8a
diff --git a/core/src/lib.rs b/src/common/mod.rs
similarity index 88%
copy from core/src/lib.rs
copy to src/common/mod.rs
index f94e272..cd8c341 100644
--- a/core/src/lib.rs
+++ b/src/common/mod.rs
@@ -5,13 +5,14 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
-
+pub mod random_generator;
+pub mod time;
diff --git a/core/src/lib.rs b/src/common/random_generator.rs
similarity index 77%
copy from core/src/lib.rs
copy to src/common/random_generator.rs
index f94e272..6c64f5b 100644
--- a/core/src/lib.rs
+++ b/src/common/random_generator.rs
@@ -5,13 +5,21 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
+use uuid::Uuid;
+pub struct RandomGenerator;
+
+impl RandomGenerator {
+ pub fn generate() -> String {
+ Uuid::new_v4().as_u128().to_string()
+ }
+}
diff --git a/core/src/lib.rs b/src/common/time.rs
similarity index 81%
copy from core/src/lib.rs
copy to src/common/time.rs
index f94e272..8c28600 100644
--- a/core/src/lib.rs
+++ b/src/common/time.rs
@@ -5,13 +5,16 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
-
+pub trait TimeFetcher {
+ // Get current UNIX timestamp with sec resolution.
+ fn get(&self) -> i64;
+}
diff --git a/core/src/lib.rs b/src/context/mod.rs
similarity index 85%
copy from core/src/lib.rs
copy to src/context/mod.rs
index f94e272..3e9e727 100644
--- a/core/src/lib.rs
+++ b/src/context/mod.rs
@@ -5,13 +5,15 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
-
+pub mod propagation;
+pub mod system_time;
+pub mod trace_context;
diff --git a/src/context/propagation/context.rs b/src/context/propagation/context.rs
new file mode 100644
index 0000000..c72f3aa
--- /dev/null
+++ b/src/context/propagation/context.rs
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+pub static SKYWALKING_HTTP_CONTEXT_HEADER_KEY: &str = "sw8";
+
+pub struct PropagationContext {
+ /// It defines whether next span should be trace or not.
+ /// In SkyWalking, If `do_sample == true`, the span should be reported to
+ /// OAP server and can be analyzed.
+ pub do_sample: bool,
+
+ /// It defines trace ID that previous span has. It expresses unique value of entire trace.
+ pub parent_trace_id: String,
+
+ /// It defines segment ID that previos span has. It expresses unique value of entire trace.
+ pub parent_trace_segment_id: String,
+
+ /// It defines parent span's span ID.
+ pub parent_span_id: i32,
+
+ /// Service name of service parent belongs.
+ pub parent_service: String,
+
+ /// Instance name of service parent belongs.
+ pub parent_service_instance: String,
+
+ /// An endpoint name that parent requested to.
+ pub destination_endpoint: String,
+
+ /// An address that parent requested to. It can be authority or network address.
+ pub destination_address: String,
+}
+
+/// PropagationContext carries the context which include trace infomation.
+/// In general, this context will be used if you create new TraceContext after received
+/// decoded context that should be packed in `sw8` header.
+impl PropagationContext {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ do_sample: bool,
+ parent_trace_id: String,
+ parent_trace_segment_id: String,
+ parent_span_id: i32,
+ parent_service: String,
+ parent_service_instance: String,
+ destination_endpoint: String,
+ destination_address: String,
+ ) -> PropagationContext {
+ PropagationContext {
+ do_sample,
+ parent_trace_id,
+ parent_trace_segment_id,
+ parent_span_id,
+ parent_service,
+ parent_service_instance,
+ destination_endpoint,
+ destination_address,
+ }
+ }
+}
diff --git a/src/context/propagation/decoder.rs b/src/context/propagation/decoder.rs
new file mode 100644
index 0000000..155af43
--- /dev/null
+++ b/src/context/propagation/decoder.rs
@@ -0,0 +1,77 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+use crate::context::propagation::context::PropagationContext;
+use base64::decode;
+
+/// Decode context value packed in `sw8` header.
+pub fn decode_propagation(header_value: &str) -> Result<PropagationContext, &str> {
+ let pieces: Vec<&str> = header_value.split('-').collect();
+
+ if pieces.len() != 8 {
+ return Err("failed to parse propagation context: it must have 8 properties.");
+ }
+
+ let do_sample = try_parse_sample_status(pieces[0])?;
+ let parent_trace_id = b64_encoded_into_string(pieces[1])?;
+ let parent_trace_segment_id = b64_encoded_into_string(pieces[2])?;
+ let parent_span_id: i32 = try_parse_parent_span_id(pieces[3])?;
+ let parent_service = b64_encoded_into_string(pieces[4])?;
+ let parent_service_instance = b64_encoded_into_string(pieces[5])?;
+ let destination_endpoint = b64_encoded_into_string(pieces[6])?;
+ let destination_address = b64_encoded_into_string(pieces[7])?;
+
+ let context = PropagationContext::new(
+ do_sample,
+ parent_trace_id,
+ parent_trace_segment_id,
+ parent_span_id,
+ parent_service,
+ parent_service_instance,
+ destination_endpoint,
+ destination_address,
+ );
+
+ Ok(context)
+}
+
+fn try_parse_parent_span_id(id: &str) -> Result<i32, &str> {
+ if let Ok(result) = id.parse::<i32>() {
+ Ok(result)
+ } else {
+ Err("failed to parse span id from parent.")
+ }
+}
+
+fn try_parse_sample_status(status: &str) -> Result<bool, &str> {
+ if status == "0" {
+ Ok(false)
+ } else if status == "1" {
+ Ok(true)
+ } else {
+ Err("failed to parse sample status.")
+ }
+}
+
+fn b64_encoded_into_string(enc: &str) -> Result<String, &str> {
+ if let Ok(result) = decode(enc) {
+ if let Ok(decoded_str) = String::from_utf8(result) {
+ return Ok(decoded_str);
+ }
+ }
+
+ Err("failed to decode value.")
+}
diff --git a/src/context/propagation/encoder.rs b/src/context/propagation/encoder.rs
new file mode 100644
index 0000000..937e5f7
--- /dev/null
+++ b/src/context/propagation/encoder.rs
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+use crate::context::trace_context::TracingContext;
+use base64::encode;
+
+/// Encode TracingContext to carry current trace info to the destination of RPC call.
+/// In general, the output of this function will be packed in `sw8` header in HTTP call.
+pub fn encode_propagation(context: &TracingContext, endpoint: &str, address: &str) -> String {
+ let mut res = String::new();
+
+ res += "1-";
+ res += format!("{}-", encode(context.trace_id.to_string())).as_str();
+ res += format!("{}-", encode(context.trace_segment_id.to_string())).as_str();
+ res += format!("{}-", context.next_span_id.to_string()).as_str();
+ res += format!("{}-", encode(context.service.as_str())).as_str();
+ res += format!("{}-", encode(context.service_instance.as_str())).as_str();
+ res += format!("{}-", encode(endpoint)).as_str();
+ res += &encode(address);
+ res
+}
diff --git a/core/src/lib.rs b/src/context/propagation/mod.rs
similarity index 87%
copy from core/src/lib.rs
copy to src/context/propagation/mod.rs
index f94e272..6c522f3 100644
--- a/core/src/lib.rs
+++ b/src/context/propagation/mod.rs
@@ -5,13 +5,15 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
-
+pub mod context;
+pub mod decoder;
+pub mod encoder;
diff --git a/core/src/lib.rs b/src/context/system_time.rs
similarity index 65%
copy from core/src/lib.rs
copy to src/context/system_time.rs
index f94e272..69f2423 100644
--- a/core/src/lib.rs
+++ b/src/context/system_time.rs
@@ -5,13 +5,26 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
+use crate::common::time::TimeFetcher;
+use std::time::{SystemTime, UNIX_EPOCH};
+#[derive(Default)]
+pub struct UnixTimeStampFetcher {}
+
+impl TimeFetcher for UnixTimeStampFetcher {
+ fn get(&self) -> i64 {
+ SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs() as i64
+ }
+}
diff --git a/src/context/trace_context.rs b/src/context/trace_context.rs
new file mode 100644
index 0000000..ee34b73
--- /dev/null
+++ b/src/context/trace_context.rs
@@ -0,0 +1,355 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+use crate::common::random_generator::RandomGenerator;
+use crate::common::time::TimeFetcher;
+use crate::context::propagation::context::PropagationContext;
+use crate::skywalking_proto::v3::{
+ KeyStringValuePair, Log, RefType, SegmentObject, SegmentReference, SpanLayer, SpanObject,
+ SpanType,
+};
+use std::sync::Arc;
+
+use super::system_time::UnixTimeStampFetcher;
+
+/// Span is a concept that represents trace information for a single RPC.
+/// The Rust SDK supports Entry Span to represent inbound to a service
+/// and Exit Span to represent outbound from a service.
+///
+/// # Example
+///
+/// ```
+/// async fn handle_request() {
+/// let mut ctx = TracingContext::default("svc", "ins");
+/// {
+/// // Generate an Entry Span when a request
+/// // is received. An Entry Span is generated only once per context.
+/// let span = ctx.create_entry_span("operation1").unwrap();
+///
+/// // Something...
+///
+/// {
+/// // Generates an Exit Span when executing an RPC.
+/// let span2 = ctx.create_exit_span("operation2").unwrap();
+///
+/// // Something...
+///
+/// ctx.finalize_span(span2);
+/// }
+///
+/// ctx.finalize_span(span);
+/// }
+/// }
+/// ```
+pub struct Span {
+ span_internal: SpanObject,
+ time_fetcher: Arc<dyn TimeFetcher + Sync + Send>,
+}
+
+static SKYWALKING_RUST_COMPONENT_ID: i32 = 11000;
+
+impl Span {
+ pub fn new(
+ parent_span_id: i32,
+ operation_name: String,
+ remote_peer: String,
+ span_type: SpanType,
+ span_layer: SpanLayer,
+ skip_analysis: bool,
+ time_fetcher: Arc<dyn TimeFetcher + Sync + Send>,
+ ) -> Self {
+ let span_internal = SpanObject {
+ span_id: parent_span_id + 1,
+ parent_span_id,
+ start_time: time_fetcher.get(),
+ end_time: 0, // not set
+ refs: Vec::<SegmentReference>::new(),
+ operation_name,
+ peer: remote_peer,
+ span_type: span_type as i32,
+ span_layer: span_layer as i32,
+ component_id: SKYWALKING_RUST_COMPONENT_ID,
+ is_error: false,
+ tags: Vec::<KeyStringValuePair>::new(),
+ logs: Vec::<Log>::new(),
+ skip_analysis,
+ };
+
+ Span {
+ span_internal,
+ time_fetcher,
+ }
+ }
+
+ /// Close span. It only registers end time to the span.
+ pub fn close(&mut self) {
+ self.span_internal.end_time = self.time_fetcher.get();
+ }
+
+ pub fn span_object(&self) -> &SpanObject {
+ &self.span_internal
+ }
+
+ /// Add logs to the span.
+ pub fn add_log(&mut self, message: Vec<(&str, &str)>) {
+ let log = Log {
+ time: self.time_fetcher.get(),
+ data: message
+ .into_iter()
+ .map(|v| {
+ let (key, value) = v;
+ KeyStringValuePair {
+ key: key.to_string(),
+ value: value.to_string(),
+ }
+ })
+ .collect(),
+ };
+ self.span_internal.logs.push(log);
+ }
+
+ /// Add tag to the span.
+ pub fn add_tag(&mut self, tag: (&str, &str)) {
+ let (key, value) = tag;
+ self.span_internal.tags.push(KeyStringValuePair {
+ key: key.to_string(),
+ value: value.to_string(),
+ });
+ }
+
+ fn add_segment_reference(&mut self, segment_reference: SegmentReference) {
+ self.span_internal.refs.push(segment_reference);
+ }
+}
+
+pub struct TracingContext {
+ pub trace_id: String,
+ pub trace_segment_id: String,
+ pub service: String,
+ pub service_instance: String,
+ pub next_span_id: i32,
+ pub spans: Vec<Box<Span>>,
+ time_fetcher: Arc<dyn TimeFetcher + Sync + Send>,
+ segment_link: Option<PropagationContext>,
+}
+
+impl TracingContext {
+ /// Generate a new trace context. Typically called when no context has
+ /// been propagated and a new trace is to be started.
+ pub fn default(service_name: &str, instance_name: &str) -> Self {
+ let unix_time_fetcher = UnixTimeStampFetcher {};
+ TracingContext::default_internal(Arc::new(unix_time_fetcher), service_name, instance_name)
+ }
+
+ pub fn default_internal(
+ time_fetcher: Arc<dyn TimeFetcher + Sync + Send>,
+ service_name: &str,
+ instance_name: &str,
+ ) -> Self {
+ TracingContext {
+ trace_id: RandomGenerator::generate(),
+ trace_segment_id: RandomGenerator::generate(),
+ service: String::from(service_name),
+ service_instance: String::from(instance_name),
+ next_span_id: 0,
+ time_fetcher,
+ spans: Vec::new(),
+ segment_link: None,
+ }
+ }
+
+ /// Generate a new trace context using the propagated context.
+ /// They should be propagated on `sw8` header in HTTP request with encoded form.
+ /// You can retrieve decoded context with `skywalking_rust::context::propagation::encoder::encode_propagation`
+ pub fn from_propagation_context(
+ service_name: &str,
+ instance_name: &str,
+ context: PropagationContext,
+ ) -> Self {
+ let unix_time_fetcher = UnixTimeStampFetcher {};
+ TracingContext::from_propagation_context_internal(
+ Arc::new(unix_time_fetcher),
+ service_name,
+ instance_name,
+ context,
+ )
+ }
+
+ pub fn from_propagation_context_internal(
+ time_fetcher: Arc<dyn TimeFetcher + Sync + Send>,
+ service_name: &str,
+ instance_name: &str,
+ context: PropagationContext,
+ ) -> Self {
+ TracingContext {
+ trace_id: context.parent_trace_id.clone(),
+ trace_segment_id: RandomGenerator::generate(),
+ service: service_name.to_string(),
+ service_instance: instance_name.to_string(),
+ next_span_id: 0,
+ time_fetcher,
+ spans: Vec::new(),
+ segment_link: Some(context),
+ }
+ }
+
+ /// A wrapper of create entry span, which close generated span automatically.
+ /// Note that, we may use async operation in closure. But that is not unstable feature in 2021/12.
+ /// https://github.com/rust-lang/rust/issues/62290
+ /// So we should create and close spans manually in general.
+ pub fn entry<F: FnMut(&Span)>(
+ &mut self,
+ operation_name: &str,
+ mut process_fn: F,
+ ) -> Result<(), &str> {
+ match self.create_entry_span(operation_name) {
+ Ok(mut span) => {
+ process_fn(span.as_ref());
+ span.close();
+ Ok(())
+ }
+ Err(message) => Err(message),
+ }
+ }
+
+ /// Create a new entry span, which is an initiator of collection of spans.
+ /// This should be called by invocation of the function which is triggered by
+ /// external service.
+ pub fn create_entry_span(&mut self, operation_name: &str) -> Result<Box<Span>, &'static str> {
+ if self.next_span_id >= 1 {
+ return Err("entry span have already exist.");
+ }
+
+ let mut span = Box::new(Span::new(
+ self.next_span_id,
+ operation_name.to_string(),
+ String::default(),
+ SpanType::Entry,
+ SpanLayer::Http,
+ false,
+ self.time_fetcher.clone(),
+ ));
+
+ if self.segment_link.is_some() {
+ span.add_segment_reference(SegmentReference {
+ ref_type: RefType::CrossProcess as i32,
+ trace_id: self.trace_id.clone(),
+ parent_trace_segment_id: self
+ .segment_link
+ .as_ref()
+ .unwrap()
+ .parent_trace_segment_id
+ .clone(),
+ parent_span_id: self.segment_link.as_ref().unwrap().parent_span_id,
+ parent_service: self.segment_link.as_ref().unwrap().parent_service.clone(),
+ parent_service_instance: self
+ .segment_link
+ .as_ref()
+ .unwrap()
+ .parent_service_instance
+ .clone(),
+ parent_endpoint: self
+ .segment_link
+ .as_ref()
+ .unwrap()
+ .destination_endpoint
+ .clone(),
+ network_address_used_at_peer: self
+ .segment_link
+ .as_ref()
+ .unwrap()
+ .destination_address
+ .clone(),
+ });
+ }
+ self.next_span_id += 1;
+ Ok(span)
+ }
+
+ /// A wrapper of create exit span, which close generated span automatically.
+ /// Note that, we may use async operation in closure. But that is not unstable feature in 2021/12.
+ /// https://github.com/rust-lang/rust/issues/62290
+ /// So we should create and close spans manually in general.
+ pub fn exit<F: FnMut(&Span)>(
+ &mut self,
+ operation_name: &str,
+ remote_peer: &str,
+ mut process_fn: F,
+ ) -> Result<(), &str> {
+ match self.create_exit_span(operation_name, remote_peer) {
+ Ok(mut span) => {
+ process_fn(span.as_ref());
+ span.close();
+ Ok(())
+ }
+ Err(message) => Err(message),
+ }
+ }
+
+ /// Create a new exit span, which will be created when tracing context will generate
+ /// new span for function invocation.
+ /// Currently, this SDK supports RPC call. So we must set `remote_peer`.
+ pub fn create_exit_span(
+ &mut self,
+ operation_name: &str,
+ remote_peer: &str,
+ ) -> Result<Box<Span>, &'static str> {
+ if self.next_span_id == 0 {
+ return Err("entry span must be existed.");
+ }
+
+ let span = Box::new(Span::new(
+ self.next_span_id,
+ operation_name.to_string(),
+ remote_peer.to_string(),
+ SpanType::Exit,
+ SpanLayer::Http,
+ false,
+ self.time_fetcher.clone(),
+ ));
+ self.next_span_id += 1;
+ Ok(span)
+ }
+
+ /// Close span. We can't use closed span after finalize called.
+ pub fn finalize_span(&mut self, mut span: Box<Span>) {
+ span.close();
+ self.spans.push(span);
+ }
+
+ pub fn finalize_span_for_test(&self, span: &mut Box<Span>) {
+ span.close();
+ }
+
+ /// It converts tracing context into segment object.
+ /// This conversion should be done before sending segments into OAP.
+ pub fn convert_segment_object(&self) -> SegmentObject {
+ let mut objects = Vec::<SpanObject>::new();
+
+ for span in self.spans.iter() {
+ objects.push(span.span_internal.clone());
+ }
+
+ SegmentObject {
+ trace_id: self.trace_id.to_string(),
+ trace_segment_id: self.trace_segment_id.to_string(),
+ spans: objects,
+ service: self.service.clone(),
+ service_instance: self.service_instance.clone(),
+ is_size_limited: false,
+ }
+ }
+}
diff --git a/core/src/skywalking/agent/mod.rs b/src/lib.rs
similarity index 79%
rename from core/src/skywalking/agent/mod.rs
rename to src/lib.rs
index 7cf36a6..0793220 100644
--- a/core/src/skywalking/agent/mod.rs
+++ b/src/lib.rs
@@ -5,16 +5,21 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub use context_manager::ContextManager;
+pub mod skywalking_proto {
+ pub mod v3 {
+ tonic::include_proto!("skywalking.v3");
+ }
+}
-pub mod context_manager;
+pub mod common;
+pub mod context;
pub mod reporter;
-
diff --git a/src/reporter/grpc.rs b/src/reporter/grpc.rs
new file mode 100644
index 0000000..43f9664
--- /dev/null
+++ b/src/reporter/grpc.rs
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+use crate::context::trace_context::TracingContext;
+use crate::skywalking_proto::v3::trace_segment_report_service_client::TraceSegmentReportServiceClient;
+use crate::skywalking_proto::v3::SegmentObject;
+use tokio::sync::mpsc;
+use tonic::transport::Channel;
+
+pub type ReporterClient = TraceSegmentReportServiceClient<Channel>;
+
+async fn flush(client: &mut ReporterClient, context: SegmentObject) -> Result<(), tonic::Status> {
+ let stream = async_stream::stream! {
+ yield context;
+ };
+ match client.collect(stream).await {
+ Ok(_) => Ok(()),
+ Err(e) => Err(e),
+ }
+}
+
+pub struct Reporter {}
+
+static CHANNEL_BUF_SIZE: usize = 1024;
+
+pub type ContextReporter = mpsc::Sender<TracingContext>;
+
+impl Reporter {
+ /// Open gRPC client stream to send collected trace context.
+ /// This function generates a new async task which watch to arrive new trace context.
+ /// We can send collected context to push into sender.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use tokio;
+ ///
+ /// #[tokio::main]
+ /// async fn main {
+ /// let tx = Reporter::start("localhost:12800");
+ /// tx.send(context).await;
+ /// }
+ /// ```
+ pub async fn start(address: &str) -> ContextReporter {
+ let (tx, mut rx): (mpsc::Sender<TracingContext>, mpsc::Receiver<TracingContext>) =
+ mpsc::channel(CHANNEL_BUF_SIZE);
+ let mut reporter = ReporterClient::connect(address.to_string()).await.unwrap();
+ tokio::spawn(async move {
+ while let Some(message) = rx.recv().await {
+ flush(&mut reporter, message.convert_segment_object())
+ .await
+ .unwrap();
+ }
+ });
+ tx
+ }
+}
diff --git a/core/src/lib.rs b/src/reporter/mod.rs
similarity index 91%
rename from core/src/lib.rs
rename to src/reporter/mod.rs
index f94e272..3a196cf 100644
--- a/core/src/lib.rs
+++ b/src/reporter/mod.rs
@@ -5,13 +5,13 @@
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
-pub mod skywalking;
-
+pub mod grpc;
diff --git a/tests/e2e/Cargo.lock b/tests/e2e/Cargo.lock
new file mode 100644
index 0000000..197c8a4
--- /dev/null
+++ b/tests/e2e/Cargo.lock
@@ -0,0 +1,1050 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
+
+[[package]]
+name = "async-stream"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bytes"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "2.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "e2e"
+version = "0.1.0"
+dependencies = [
+ "hyper",
+ "skywalking_rust",
+ "structopt",
+ "tokio",
+]
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "fixedbitset"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "futures-channel"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
+
+[[package]]
+name = "futures-task"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
+
+[[package]]
+name = "futures-util"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
+dependencies = [
+ "autocfg",
+ "futures-core",
+ "futures-task",
+ "pin-project-lite",
+ "pin-utils",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "h2"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "http"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
+
+[[package]]
+name = "httpdate"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
+
+[[package]]
+name = "hyper"
+version = "0.14.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-timeout"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
+dependencies = [
+ "hyper",
+ "pin-project-lite",
+ "tokio",
+ "tokio-io-timeout",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.112"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
+
+[[package]]
+name = "lock_api"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "mio"
+version = "0.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
+dependencies = [
+ "libc",
+ "log",
+ "miow",
+ "ntapi",
+ "winapi",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "multimap"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
+
+[[package]]
+name = "ntapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
+
+[[package]]
+name = "parking_lot"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
+dependencies = [
+ "cfg-if",
+ "instant",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "winapi",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+
+[[package]]
+name = "petgraph"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "prost"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020"
+dependencies = [
+ "bytes",
+ "prost-derive",
+]
+
+[[package]]
+name = "prost-build"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
+dependencies = [
+ "bytes",
+ "heck",
+ "itertools",
+ "log",
+ "multimap",
+ "petgraph",
+ "prost",
+ "prost-types",
+ "tempfile",
+ "which",
+]
+
+[[package]]
+name = "prost-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba"
+dependencies = [
+ "anyhow",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "prost-types"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b"
+dependencies = [
+ "bytes",
+ "prost",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "serde"
+version = "1.0.132"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "skywalking_rust"
+version = "0.0.1"
+dependencies = [
+ "async-stream",
+ "base64",
+ "bytes",
+ "prost",
+ "prost-derive",
+ "tokio",
+ "tonic",
+ "tonic-build",
+ "uuid",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
+
+[[package]]
+name = "smallvec"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
+
+[[package]]
+name = "socket2"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "structopt"
+version = "0.3.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
+dependencies = [
+ "clap",
+ "lazy_static",
+ "structopt-derive",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "tokio"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
+dependencies = [
+ "bytes",
+ "libc",
+ "memchr",
+ "mio",
+ "num_cpus",
+ "once_cell",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "tokio-macros",
+ "winapi",
+]
+
+[[package]]
+name = "tokio-io-timeout"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90c49f106be240de154571dd31fbe48acb10ba6c6dd6f6517ad603abffa42de9"
+dependencies = [
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tonic"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "796c5e1cd49905e65dd8e700d4cb1dffcbfdb4fc9d017de08c1a537afd83627c"
+dependencies = [
+ "async-stream",
+ "async-trait",
+ "base64",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-timeout",
+ "percent-encoding",
+ "pin-project",
+ "prost",
+ "prost-derive",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+ "tracing-futures",
+]
+
+[[package]]
+name = "tonic-build"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12b52d07035516c2b74337d2ac7746075e7dcae7643816c1b12c5ff8a7484c08"
+dependencies = [
+ "proc-macro2",
+ "prost-build",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tower"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5651b5f6860a99bd1adb59dbfe1db8beb433e73709d9032b413a77e2fb7c066a"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "indexmap",
+ "pin-project",
+ "pin-project-lite",
+ "rand",
+ "slab",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62"
+
+[[package]]
+name = "tower-service"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+
+[[package]]
+name = "tracing"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
+dependencies = [
+ "cfg-if",
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "tracing-futures"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
+dependencies = [
+ "pin-project",
+ "tracing",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom",
+ "serde",
+]
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "which"
+version = "4.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
+dependencies = [
+ "either",
+ "lazy_static",
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/tests/e2e/Cargo.toml b/tests/e2e/Cargo.toml
new file mode 100644
index 0000000..6a5cf5b
--- /dev/null
+++ b/tests/e2e/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "e2e"
+version = "0.1.0"
+authors = ["Shikugawa <Shikugawa@gmail.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+skywalking_rust = { path = "../../" }
+hyper = { version = "0.14", features = ["full"] }
+tokio = { version = "1", features = ["full"] }
+structopt = "0.3"
diff --git a/tests/e2e/data/expected_context.yaml b/tests/e2e/data/expected_context.yaml
new file mode 100644
index 0000000..79f78b5
--- /dev/null
+++ b/tests/e2e/data/expected_context.yaml
@@ -0,0 +1,56 @@
+segmentItems:
+- segmentSize: 1
+ segments:
+ - segmentId: not null
+ spans:
+ - componentId: 11000
+ endTime: gt 0
+ isError: false
+ operationId: 0
+ operationName: /pong
+ parentSpanId: 1
+ peer: consumer:8082
+ skipAnalysis: false
+ spanId: 2
+ spanLayer: Http
+ spanType: Exit
+ startTime: gt 0
+ - componentId: 11000
+ endTime: gt 0
+ isError: false
+ operationId: 0
+ operationName: /ping
+ parentSpanId: 0
+ peer: ''
+ skipAnalysis: false
+ spanId: 1
+ spanLayer: Http
+ spanType: Entry
+ startTime: gt 0
+ serviceName: producer
+- segmentSize: 1
+ segments:
+ - segmentId: not null
+ spans:
+ - componentId: 11000
+ endTime: gt 0
+ isError: false
+ operationId: 0
+ operationName: /pong
+ parentSpanId: 0
+ peer: ''
+ refs:
+ - networkAddress: consumer:8082
+ parentEndpoint: /pong
+ parentService: producer
+ parentServiceInstance: node_0
+ parentSpanId: 2
+ parentTraceSegmentId: not null
+ refType: CrossProcess
+ traceId: not null
+ skipAnalysis: false
+ spanId: 1
+ spanLayer: Http
+ spanType: Entry
+ startTime: gt 0
+ serviceName: consumer
\ No newline at end of file
diff --git a/tests/e2e/docker/Dockerfile b/tests/e2e/docker/Dockerfile
new file mode 100644
index 0000000..2ec7258
--- /dev/null
+++ b/tests/e2e/docker/Dockerfile
@@ -0,0 +1,5 @@
+FROM rust:1.50.0
+RUN apt update && apt install -y protobuf-compiler
+RUN rustup component add rustfmt
+COPY . /tmp
+WORKDIR tmp/tests/e2e
diff --git a/tests/e2e/docker/Dockerfile.tool b/tests/e2e/docker/Dockerfile.tool
new file mode 100644
index 0000000..74ef01c
--- /dev/null
+++ b/tests/e2e/docker/Dockerfile.tool
@@ -0,0 +1,15 @@
+FROM openjdk:8
+WORKDIR /tests
+ARG COMMIT_HASH=8db606f3470cce75c1b013ae498ac93b862b75b7
+ADD https://github.com/apache/skywalking-agent-test-tool/archive/${COMMIT_HASH}.tar.gz .
+RUN tar -xf ${COMMIT_HASH}.tar.gz --strip 1
+RUN rm ${COMMIT_HASH}.tar.gz
+RUN ./mvnw -B -DskipTests package
+
+FROM openjdk:8
+EXPOSE 19876 12800
+WORKDIR /tests
+COPY --from=0 /tests/dist/skywalking-mock-collector.tar.gz /tests
+RUN tar -xf skywalking-mock-collector.tar.gz --strip 1
+RUN chmod +x bin/collector-startup.sh
+ENTRYPOINT bin/collector-startup.sh
diff --git a/tests/e2e/run_e2e.py b/tests/e2e/run_e2e.py
new file mode 100644
index 0000000..cd2e1c9
--- /dev/null
+++ b/tests/e2e/run_e2e.py
@@ -0,0 +1,61 @@
+import os
+import sys
+import time
+from difflib import Differ
+from os.path import dirname
+
+import argparse
+import yaml
+import requests
+import time
+
+try:
+ from yaml import CSafeLoader as Loader
+except ImportError:
+ from yaml import SafeLoader as Loader
+
+def validate(expected_file_name):
+ with open(expected_file_name) as expected_data_file:
+ expected_data = os.linesep.join(expected_data_file.readlines())
+
+ response = requests.post(url='http://0.0.0.0:12800/dataValidate', data=expected_data)
+
+ if response.status_code != 200:
+ res = requests.get('http://0.0.0.0:12800/receiveData')
+ actual_data = yaml.dump(yaml.load(res.content, Loader=Loader))
+
+ differ = Differ()
+ diff_list = list(differ.compare(
+ actual_data.splitlines(keepends=True),
+ yaml.dump(yaml.load(expected_data, Loader=Loader)).splitlines(keepends=True)
+ ))
+
+ print('diff list: ')
+ sys.stdout.writelines(diff_list)
+
+ return response
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--expected_file', help='File name which includes expected reported value')
+ parser.add_argument('--max_retry_times', help='Max retry times', type=int)
+ parser.add_argument('--target_path', help='Specify target path')
+
+ args = parser.parse_args()
+
+ retry_times = 0
+ while True:
+ if retry_times > args.max_retry_times:
+ raise RuntimeError("Max retry times exceeded")
+
+ try:
+ requests.get('http://0.0.0.0:8081{0}'.format(args.target_path), timeout=5)
+ except Exception as e:
+ print(e)
+ retry_times += 1
+ time.sleep(2)
+ continue
+
+ res = validate(args.expected_file)
+ assert res.status_code == 200
+ break
diff --git a/tests/e2e/src/main.rs b/tests/e2e/src/main.rs
new file mode 100644
index 0000000..cc9f76c
--- /dev/null
+++ b/tests/e2e/src/main.rs
@@ -0,0 +1,135 @@
+use hyper::client::HttpConnector;
+use hyper::service::{make_service_fn, service_fn};
+use hyper::{Body, Client, Method, Request, Response, Server, StatusCode};
+use skywalking_rust::context::propagation::context::SKYWALKING_HTTP_CONTEXT_HEADER_KEY;
+use skywalking_rust::context::propagation::decoder::decode_propagation;
+use skywalking_rust::context::propagation::encoder::encode_propagation;
+use skywalking_rust::context::trace_context::TracingContext;
+use skywalking_rust::reporter::grpc::Reporter;
+use std::convert::Infallible;
+use std::net::SocketAddr;
+use structopt::StructOpt;
+use tokio::sync::mpsc;
+
+static NOT_FOUND_MSG: &str = "not found";
+
+async fn handle_ping(
+ _req: Request<Body>,
+ client: Client<HttpConnector>,
+ tx: mpsc::Sender<TracingContext>,
+) -> Result<Response<Body>, Infallible> {
+ let mut context = TracingContext::default("producer", "node_0");
+ let span = context.create_entry_span("/ping").unwrap();
+ {
+ let span2 = context.create_exit_span("/pong", "consumer:8082").unwrap();
+ let header = encode_propagation(&context, "/pong", "consumer:8082");
+ let req = Request::builder()
+ .method(Method::GET)
+ .header(SKYWALKING_HTTP_CONTEXT_HEADER_KEY, header)
+ .uri("http://consumer:8082/pong")
+ .body(Body::from(""))
+ .unwrap();
+
+ client.request(req).await.unwrap();
+ context.finalize_span(span2);
+ }
+ context.finalize_span(span);
+ let _ = tx.send(context).await;
+ Ok(Response::new(Body::from("hoge")))
+}
+
+async fn producer_response(
+ _req: Request<Body>,
+ client: Client<HttpConnector>,
+ tx: mpsc::Sender<TracingContext>,
+) -> Result<Response<Body>, Infallible> {
+ match (_req.method(), _req.uri().path()) {
+ (&Method::GET, "/ping") => handle_ping(_req, client, tx).await,
+ _ => Ok(Response::builder()
+ .status(StatusCode::NOT_FOUND)
+ .body(Body::from(NOT_FOUND_MSG))
+ .unwrap()),
+ }
+}
+
+async fn run_producer_service(host: [u8; 4], tx: mpsc::Sender<TracingContext>) {
+ let client = Client::new();
+ let make_svc = make_service_fn(|_| {
+ let tx = tx.clone();
+ let client = client.clone();
+
+ async {
+ Ok::<_, Infallible>(service_fn(move |req| {
+ producer_response(req, client.to_owned(), tx.to_owned())
+ }))
+ }
+ });
+ let addr = SocketAddr::from((host, 8081));
+ let server = Server::bind(&addr).serve(make_svc);
+
+ if let Err(e) = server.await {
+ eprintln!("server error: {}", e);
+ }
+}
+
+async fn handle_pong(
+ _req: Request<Body>,
+ tx: mpsc::Sender<TracingContext>,
+) -> Result<Response<Body>, Infallible> {
+ let ctx = decode_propagation(
+ &_req.headers()[SKYWALKING_HTTP_CONTEXT_HEADER_KEY]
+ .to_str()
+ .unwrap(),
+ )
+ .unwrap();
+ let mut context = TracingContext::from_propagation_context("consumer", "node_0", ctx);
+ let span = context.create_entry_span("/pong").unwrap();
+ context.finalize_span(span);
+ let _ = tx.send(context).await;
+ Ok(Response::new(Body::from("hoge")))
+}
+
+async fn consumer_response(
+ _req: Request<Body>,
+ tx: mpsc::Sender<TracingContext>,
+) -> Result<Response<Body>, Infallible> {
+ match (_req.method(), _req.uri().path()) {
+ (&Method::GET, "/pong") => handle_pong(_req, tx).await,
+ _ => Ok(Response::builder()
+ .status(StatusCode::NOT_FOUND)
+ .body(Body::from(NOT_FOUND_MSG))
+ .unwrap()),
+ }
+}
+
+async fn run_consumer_service(host: [u8; 4], tx: mpsc::Sender<TracingContext>) {
+ let make_svc = make_service_fn(|_| {
+ let tx = tx.clone();
+ async { Ok::<_, Infallible>(service_fn(move |req| consumer_response(req, tx.to_owned()))) }
+ });
+ let addr = SocketAddr::from((host, 8082));
+ let server = Server::bind(&addr).serve(make_svc);
+
+ if let Err(e) = server.await {
+ eprintln!("server error: {}", e);
+ }
+}
+
+#[derive(StructOpt)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(short, long)]
+ mode: String,
+}
+
+#[tokio::main]
+async fn main() {
+ let opt = Opt::from_args();
+ let tx = Reporter::start("http://collector:19876").await;
+
+ if opt.mode == "consumer" {
+ run_consumer_service([0, 0, 0, 0], tx).await;
+ } else if opt.mode == "producer" {
+ run_producer_service([0, 0, 0, 0], tx).await;
+ }
+}
diff --git a/tests/propagation.rs b/tests/propagation.rs
new file mode 100644
index 0000000..99ad4fb
--- /dev/null
+++ b/tests/propagation.rs
@@ -0,0 +1,81 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#![allow(unused_imports)]
+use skywalking_rust::common::time::TimeFetcher;
+use skywalking_rust::context::propagation::context::PropagationContext;
+use skywalking_rust::context::propagation::decoder::decode_propagation;
+use skywalking_rust::context::propagation::encoder::encode_propagation;
+use skywalking_rust::context::trace_context::TracingContext;
+use std::sync::Arc;
+
+struct MockTimeFetcher {}
+
+impl TimeFetcher for MockTimeFetcher {
+ fn get(&self) -> i64 {
+ 100
+ }
+}
+
+#[test]
+fn basic() {
+ let data = "1-MQ==-NQ==-3-bWVzaA==-aW5zdGFuY2U=-L2FwaS92MS9oZWFsdGg=-ZXhhbXBsZS5jb206ODA4MA==";
+ let res = decode_propagation(data).unwrap();
+
+ assert_eq!(res.do_sample, true);
+ assert_eq!(res.parent_trace_id, "1");
+ assert_eq!(res.parent_trace_segment_id, "5");
+ assert_eq!(res.parent_span_id, 3);
+ assert_eq!(res.parent_service, "mesh");
+ assert_eq!(res.parent_service_instance, "instance");
+ assert_eq!(res.destination_endpoint, "/api/v1/health");
+ assert_eq!(res.destination_address, "example.com:8080");
+}
+
+#[test]
+fn less_field() {
+ let data = "1-MQ==-NQ==-3-bWVzaA==-aW5zdGFuY2U=-L2FwaS92MS9oZWFsdGg=";
+ let res = decode_propagation(data);
+
+ assert_eq!(res.is_err(), true);
+}
+
+#[test]
+fn more_field() {
+ let data = "1-MQ==-NQ==-3-bWVzaA==-aW5zdGFuY2U=-L2FwaS92MS9oZWFsdGg=-ZXhhbXBsZS5jb206ODA4MA==-hogehoge";
+ let res = decode_propagation(data);
+
+ assert_eq!(res.is_err(), true);
+}
+
+#[test]
+fn invalid_sample() {
+ let data = "3-MQ==-NQ==-3-bWVzaA==-aW5zdGFuY2U=-L2FwaS92MS9oZWFsdGg=-ZXhhbXBsZS5jb206ODA4MA==";
+ let res = decode_propagation(data);
+
+ assert_eq!(res.is_err(), true);
+}
+
+#[test]
+fn basic_encode() {
+ let time_fetcher = MockTimeFetcher {};
+ let tc = TracingContext::default_internal(Arc::new(time_fetcher), "mesh", "instance");
+ let res = encode_propagation(&tc, "/api/v1/health", "example.com:8080");
+ let res2 = decode_propagation(&res).unwrap();
+ assert_eq!(true, res2.do_sample);
+ assert_eq!("/api/v1/health", res2.destination_endpoint);
+ assert_eq!("example.com:8080", res2.destination_address)
+}
diff --git a/tests/trace_context.rs b/tests/trace_context.rs
new file mode 100644
index 0000000..eea0d0a
--- /dev/null
+++ b/tests/trace_context.rs
@@ -0,0 +1,224 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#![allow(unused_imports)]
+
+pub mod skywalking_proto {
+ pub mod v3 {
+ tonic::include_proto!("skywalking.v3");
+ }
+}
+
+use prost::Message;
+use skywalking_proto::v3::{
+ KeyStringValuePair, Log, RefType, SegmentObject, SegmentReference, SpanLayer, SpanObject,
+ SpanType,
+};
+use skywalking_rust::common::time::TimeFetcher;
+use skywalking_rust::context::propagation::context::PropagationContext;
+use skywalking_rust::context::propagation::decoder::decode_propagation;
+use skywalking_rust::context::propagation::encoder::encode_propagation;
+use skywalking_rust::context::trace_context::TracingContext;
+use std::{cell::Ref, sync::Arc};
+
+/// Serialize from A should equal Serialize from B
+#[allow(dead_code)]
+pub fn check_serialize_equivalent<M, N>(msg_a: &M, msg_b: &N)
+where
+ M: Message + Default + PartialEq,
+ N: Message + Default + PartialEq,
+{
+ let mut buf_a = Vec::new();
+ msg_a.encode(&mut buf_a).unwrap();
+ let mut buf_b = Vec::new();
+ msg_b.encode(&mut buf_b).unwrap();
+ assert_eq!(buf_a, buf_b);
+}
+
+struct MockTimeFetcher {}
+
+impl TimeFetcher for MockTimeFetcher {
+ fn get(&self) -> i64 {
+ 100
+ }
+}
+
+#[test]
+fn create_span() {
+ let time_fetcher = MockTimeFetcher {};
+ let mut context =
+ TracingContext::default_internal(Arc::new(time_fetcher), "service", "instance");
+ assert_eq!(context.service, "service");
+ assert_eq!(context.service_instance, "instance");
+
+ {
+ let mut span1 = context.create_entry_span("op1").unwrap();
+ let mut logs = Vec::<(&str, &str)>::new();
+ logs.push(("hoge", "fuga"));
+ logs.push(("hoge2", "fuga2"));
+ let expected_log_message = logs
+ .to_owned()
+ .into_iter()
+ .map(|v| {
+ let (key, value) = v;
+ KeyStringValuePair {
+ key: key.to_string(),
+ value: value.to_string(),
+ }
+ })
+ .collect();
+ let mut expected_log = Vec::<Log>::new();
+ expected_log.push(Log {
+ time: 100,
+ data: expected_log_message,
+ });
+ span1.add_log(logs);
+
+ let mut tags = Vec::<(&str, &str)>::new();
+ tags.push(("hoge", "fuga"));
+ let expected_tags = tags
+ .to_owned()
+ .into_iter()
+ .map(|v| {
+ let (key, value) = v;
+ KeyStringValuePair {
+ key: key.to_string(),
+ value: value.to_string(),
+ }
+ })
+ .collect();
+ span1.add_tag(tags[0].clone());
+
+ let span1_expected = SpanObject {
+ span_id: 1,
+ parent_span_id: 0,
+ start_time: 100,
+ end_time: 100,
+ refs: Vec::<SegmentReference>::new(),
+ operation_name: "op1".to_string(),
+ peer: String::default(),
+ span_type: SpanType::Entry as i32,
+ span_layer: SpanLayer::Http as i32,
+ component_id: 11000,
+ is_error: false,
+ tags: expected_tags,
+ logs: expected_log,
+ skip_analysis: false,
+ };
+ context.finalize_span_for_test(&mut span1);
+ check_serialize_equivalent(span1.span_object(), &span1_expected);
+ }
+
+ {
+ let span2 = context.create_entry_span("op2");
+ assert_eq!(span2.is_err(), true);
+ }
+
+ {
+ let mut span3 = context.create_exit_span("op3", "example.com/test").unwrap();
+ let span3_expected = SpanObject {
+ span_id: 2,
+ parent_span_id: 1,
+ start_time: 100,
+ end_time: 100,
+ refs: Vec::<SegmentReference>::new(),
+ operation_name: "op3".to_string(),
+ peer: "example.com/test".to_string(),
+ span_type: SpanType::Exit as i32,
+ span_layer: SpanLayer::Http as i32,
+ component_id: 11000,
+ is_error: false,
+ tags: Vec::<KeyStringValuePair>::new(),
+ logs: Vec::<Log>::new(),
+ skip_analysis: false,
+ };
+ context.finalize_span_for_test(&mut span3);
+ check_serialize_equivalent(span3.span_object(), &span3_expected);
+ }
+
+ let segment = context.convert_segment_object();
+ assert_eq!(segment.trace_id.len() != 0, true);
+ assert_eq!(segment.trace_segment_id.len() != 0, true);
+ assert_eq!(segment.service, "service");
+ assert_eq!(segment.service_instance, "instance");
+ assert_eq!(segment.is_size_limited, false);
+}
+
+#[test]
+fn create_span_from_context() {
+ let data = "1-MQ==-NQ==-3-bWVzaA==-aW5zdGFuY2U=-L2FwaS92MS9oZWFsdGg=-ZXhhbXBsZS5jb206ODA4MA==";
+ let prop = decode_propagation(data).unwrap();
+ let time_fetcher = MockTimeFetcher {};
+ let context = TracingContext::from_propagation_context_internal(
+ Arc::new(time_fetcher),
+ "service2",
+ "instance2",
+ prop,
+ );
+
+ let segment = context.convert_segment_object();
+ assert_eq!(segment.trace_id.len() != 0, true);
+ assert_eq!(segment.trace_segment_id.len() != 0, true);
+ assert_eq!(segment.service, "service2");
+ assert_eq!(segment.service_instance, "instance2");
+ assert_eq!(segment.is_size_limited, false);
+}
+
+#[test]
+fn crossprocess_test() {
+ let time_fetcher1 = MockTimeFetcher {};
+ let mut context1 =
+ TracingContext::default_internal(Arc::new(time_fetcher1), "service", "instance");
+ assert_eq!(context1.service, "service");
+ assert_eq!(context1.service_instance, "instance");
+
+ let mut span1 = context1.create_entry_span("op1").unwrap();
+ context1.finalize_span_for_test(&mut span1);
+
+ let mut span2 = context1.create_exit_span("op2", "remote_peer").unwrap();
+ context1.finalize_span_for_test(&mut span2);
+
+ let enc_prop = encode_propagation(&context1, "endpoint", "address");
+ let dec_prop = decode_propagation(&enc_prop).unwrap();
+
+ let time_fetcher2 = MockTimeFetcher {};
+ let mut context2 = TracingContext::from_propagation_context_internal(
+ Arc::new(time_fetcher2),
+ "service2",
+ "instance2",
+ dec_prop,
+ );
+
+ let mut span3 = context2.create_entry_span("op2").unwrap();
+ context2.finalize_span_for_test(&mut span3);
+
+ assert_eq!(span3.span_object().span_id, 1);
+ assert_eq!(span3.span_object().parent_span_id, 0);
+ assert_eq!(span3.span_object().refs.len(), 1);
+
+ let expected_ref = SegmentReference {
+ ref_type: RefType::CrossProcess as i32,
+ trace_id: context2.trace_id,
+ parent_trace_segment_id: context1.trace_segment_id,
+ parent_span_id: context1.next_span_id,
+ parent_service: context1.service,
+ parent_service_instance: context1.service_instance,
+ parent_endpoint: "endpoint".to_string(),
+ network_address_used_at_peer: "address".to_string(),
+ };
+
+ check_serialize_equivalent(&expected_ref, &span3.span_object().refs[0]);
+}