diff --git a/Cargo.lock b/Cargo.lock index 20ba852f..57be8aaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,6 +95,28 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "async-trait" version = "0.1.74" @@ -352,6 +374,15 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -469,6 +500,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -588,11 +629,17 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "h2" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -600,7 +647,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -944,7 +991,7 @@ source = "git+http://github.com/hasura/ndc-spec.git?tag=v0.1.0#8892f0524affd37e9 dependencies = [ "async-trait", "indexmap 2.1.0", - "opentelemetry", + "opentelemetry 0.20.0", "reqwest", "schemars", "serde", @@ -968,12 +1015,11 @@ dependencies = [ "mime", "ndc-client", "ndc-test", - "opentelemetry", + "opentelemetry 0.22.0", "opentelemetry-http", "opentelemetry-otlp", "opentelemetry-semantic-conventions", - "opentelemetry_api", - "opentelemetry_sdk", + "opentelemetry_sdk 0.22.1", "prometheus", "reqwest", "serde", @@ -1101,36 +1147,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" dependencies = [ "opentelemetry_api", - "opentelemetry_sdk", + "opentelemetry_sdk 0.20.0", +] + +[[package]] +name = "opentelemetry" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d57987be3f2aeb70d385fff9b27fb74c5723cc9a52d904d4f9c807a0667bf" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", ] [[package]] name = "opentelemetry-http" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7594ec0e11d8e33faf03530a4c49af7064ebba81c1480e01be67d90b356508b" +checksum = "7cbfa5308166ca861434f0b0913569579b8e587430a3d6bcd7fd671921ec145a" dependencies = [ "async-trait", "bytes", "http", - "opentelemetry_api", + "opentelemetry 0.22.0", "reqwest", ] [[package]] name = "opentelemetry-otlp" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5e5a5c4135864099f3faafbe939eb4d7f9b80ebf68a8448da961b32a7c1275" +checksum = "1a016b8d9495c639af2145ac22387dcb88e44118e45320d9238fbf4e7889abcb" dependencies = [ "async-trait", "futures-core", "http", + "opentelemetry 0.22.0", "opentelemetry-http", "opentelemetry-proto", "opentelemetry-semantic-conventions", - "opentelemetry_api", - "opentelemetry_sdk", + "opentelemetry_sdk 0.22.1", "prost", "reqwest", "thiserror", @@ -1140,24 +1201,21 @@ dependencies = [ [[package]] name = "opentelemetry-proto" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" +checksum = "3a8fddc9b68f5b80dae9d6f510b88e02396f006ad48cac349411fbecc80caae4" dependencies = [ - "opentelemetry_api", - "opentelemetry_sdk", + "opentelemetry 0.22.0", + "opentelemetry_sdk 0.22.1", "prost", "tonic", ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269" -dependencies = [ - "opentelemetry", -] +checksum = "f9ab5bd6c42fb9349dcf28af2ba9a0667f697f9bdcca045d39f2cec5543e2910" [[package]] name = "opentelemetry_api" @@ -1188,11 +1246,29 @@ dependencies = [ "futures-util", "once_cell", "opentelemetry_api", - "ordered-float", + "ordered-float 3.9.1", + "percent-encoding", + "rand", + "thiserror", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e90c7113be649e31e9a0f8b5ee24ed7a16923b322c3c5ab6367469c049d6b7e" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "once_cell", + "opentelemetry 0.22.0", + "ordered-float 4.2.0", "percent-encoding", "rand", - "regex", - "serde_json", "thiserror", "tokio", "tokio-stream", @@ -1207,6 +1283,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -1312,9 +1397,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.9" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" dependencies = [ "bytes", "prost-derive", @@ -1322,15 +1407,15 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.38", ] [[package]] @@ -1472,6 +1557,20 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1491,6 +1590,60 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" +dependencies = [ + "base64 0.21.5", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" + +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -1729,12 +1882,24 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1920,6 +2085,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -1947,16 +2123,16 @@ dependencies = [ [[package]] name = "tonic" -version = "0.9.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" dependencies = [ + "async-stream", "async-trait", "axum", "base64 0.21.5", "bytes", - "futures-core", - "futures-util", + "flate2", "h2", "http", "http-body", @@ -1965,7 +2141,11 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-native-certs", + "rustls-pemfile", + "rustls-pki-types", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -2060,27 +2240,31 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-opentelemetry" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc09e402904a5261e42cf27aea09ccb7d5318c6717a9eec3d8e2e65c56b18f19" +checksum = "a9be14ba1bbe4ab79e9229f7f89fab8d120b865859f10527f31c033e599d2284" dependencies = [ + "js-sys", "once_cell", - "opentelemetry", + "opentelemetry 0.22.0", + "opentelemetry_sdk 0.22.1", + "smallvec", "tracing", "tracing-core", "tracing-log", "tracing-subscriber", + "web-time", ] [[package]] @@ -2148,6 +2332,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.4.1" @@ -2293,6 +2483,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2399,3 +2599,9 @@ dependencies = [ "cfg-if", "windows-sys", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/README.md b/README.md index 0571fbb1..859270cf 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,11 @@ of requests across services. To enable tracing you must: - use the SDK option `--otlp-endpoint` e.g. `http://localhost:4317`, -- set the SDK environment variable `OTLP_ENDPOINT`, or +- set the SDK environment variable `OTEL_EXPORTER_OTLP_ENDPOINT`, or - set the `tracing` environment variable `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`. +The exporter uses gRPC protocol by default. To use HTTP protocol you must set `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf`. + For additional service information you can: - Set `OTEL_SERVICE_NAME` e.g. `ndc_hub_example` diff --git a/rust-connector-sdk/Cargo.toml b/rust-connector-sdk/Cargo.toml index 8f41a84f..ce66c26b 100644 --- a/rust-connector-sdk/Cargo.toml +++ b/rust-connector-sdk/Cargo.toml @@ -27,12 +27,11 @@ bytes = "1.5.0" clap = { version = "^4.4.7", features = ["derive", "env"] } http = "^0.2" mime = "0.3.17" -opentelemetry = { version = "^0.20", default-features = false, features = ["rt-tokio", "trace"] } -opentelemetry-http = "0.9.0" -opentelemetry-otlp = { version = "^0.13.0", features = ["reqwest-client"] } -opentelemetry-semantic-conventions = "^0.12.0" -opentelemetry_api = "^0.20.0" -opentelemetry_sdk = "^0.20.0" +opentelemetry = { version = "^0.22", default-features = false } +opentelemetry-http = "0.11.0" +opentelemetry-otlp = { version = "^0.15.0", features = ["reqwest-client", "gzip-tonic", "tls", "tls-roots", "http-proto"] } +opentelemetry-semantic-conventions = "^0.14.0" +opentelemetry_sdk = { version = "^0.22.1", features = ["rt-tokio"] } prometheus = "^0.13.3" reqwest = "^0.11.22" serde = { version = "^1.0.192", features = ["derive"] } @@ -41,7 +40,7 @@ thiserror = "^1.0" tokio = { version = "^1.34.0", features = ["fs", "signal"] } tower-http = { version = "^0.4.4", features = ["cors", "trace", "validate-request"] } tracing = "^0.1.40" -tracing-opentelemetry = "^0.20.0" +tracing-opentelemetry = "^0.23.0" tracing-subscriber = { version = "^0.3", default-features = false, features = ["ansi", "env-filter", "fmt", "json"] } url = "2.4.1" diff --git a/rust-connector-sdk/src/tracing.rs b/rust-connector-sdk/src/tracing.rs index 404ab283..61fa69ee 100644 --- a/rust-connector-sdk/src/tracing.rs +++ b/rust-connector-sdk/src/tracing.rs @@ -4,63 +4,99 @@ use std::time::Duration; use axum::body::{Body, BoxBody}; use http::{Request, Response}; -use opentelemetry::{global, sdk::propagation::TraceContextPropagator}; -use opentelemetry_api::KeyValue; +use opentelemetry::{global, KeyValue}; use opentelemetry_http::HeaderExtractor; -use opentelemetry_otlp::{WithExportConfig, OTEL_EXPORTER_OTLP_ENDPOINT_DEFAULT}; -use opentelemetry_sdk::trace::Sampler; -use tracing::Span; +use opentelemetry_otlp::{ + SpanExporterBuilder, WithExportConfig, OTEL_EXPORTER_OTLP_PROTOCOL, + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, +}; +use opentelemetry_sdk::{ + propagation::TraceContextPropagator, + trace::{self, Sampler}, + Resource, +}; +use tracing::{Level, Span}; use tracing_opentelemetry::OpenTelemetrySpanExt; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; +use tracing_subscriber::EnvFilter; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; pub fn init_tracing( service_name: &Option, otlp_endpoint: &Option, ) -> Result<(), Box> { - global::set_text_map_propagator(TraceContextPropagator::new()); - - let service_name = service_name + let trace_endpoint = otlp_endpoint .clone() - .unwrap_or(env!("CARGO_PKG_NAME").to_string()); - - let tracer = opentelemetry_otlp::new_pipeline() - .tracing() - .with_exporter( - opentelemetry_otlp::new_exporter().tonic().with_endpoint( - otlp_endpoint - .clone() - .unwrap_or(OTEL_EXPORTER_OTLP_ENDPOINT_DEFAULT.into()), - ), - ) - .with_trace_config( - opentelemetry::sdk::trace::config() - .with_resource(opentelemetry::sdk::Resource::new(vec![ - KeyValue::new( - opentelemetry_semantic_conventions::resource::SERVICE_NAME, - service_name, - ), - KeyValue::new( - opentelemetry_semantic_conventions::resource::SERVICE_VERSION, - env!("CARGO_PKG_VERSION"), - ), - ])) - .with_sampler(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))), - ) - .install_batch(opentelemetry::runtime::Tokio)?; - - tracing_subscriber::registry() - .with( - tracing_opentelemetry::layer() - .with_exception_field_propagation(true) - .with_tracer(tracer), - ) - .with(EnvFilter::builder().parse("info,otel::tracing=trace,otel=debug")?) + .or(env::var(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT).ok()); + let log_level = env::var("RUST_LOG").unwrap_or(Level::INFO.to_string()); + let subscriber = tracing_subscriber::registry() + .with(EnvFilter::builder().parse(format!("{},otel::tracing=trace,otel=debug", log_level))?) .with( tracing_subscriber::fmt::layer() .json() .with_timer(tracing_subscriber::fmt::time::time()), - ) - .init(); + ); + + match trace_endpoint { + // disable traces exporter if the endpoint is empty + None => subscriber.init(), + Some(endpoint) => { + global::set_text_map_propagator(TraceContextPropagator::new()); + + let service_name = service_name + .clone() + .unwrap_or(env!("CARGO_PKG_NAME").to_string()); + + let exporter: SpanExporterBuilder = match env::var(OTEL_EXPORTER_OTLP_PROTOCOL) { + Ok(protocol) => match protocol.as_str() { + "grpc" => Ok(opentelemetry_otlp::new_exporter() + .tonic() + .with_endpoint(endpoint) + .into()), + "http/protobuf" => Ok(opentelemetry_otlp::new_exporter() + .http() + .with_endpoint(endpoint) + .into()), + invalid => Err(format!("invalid protocol: {}", invalid)), + }, + // the default exporter protocol is grpc + Err(env::VarError::NotPresent) => Ok(opentelemetry_otlp::new_exporter() + .tonic() + .with_endpoint(endpoint) + .into()), + Err(env::VarError::NotUnicode(os_str)) => Err(format!( + "invalid protocol: {}", + os_str.to_str().unwrap_or("") + )), + }?; + + let tracer = opentelemetry_otlp::new_pipeline() + .tracing() + .with_exporter(exporter) + .with_trace_config( + trace::config() + .with_resource(Resource::new(vec![ + KeyValue::new( + opentelemetry_semantic_conventions::resource::SERVICE_NAME, + service_name, + ), + KeyValue::new( + opentelemetry_semantic_conventions::resource::SERVICE_VERSION, + env!("CARGO_PKG_VERSION"), + ), + ])) + .with_sampler(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))), + ) + .install_batch(opentelemetry_sdk::runtime::Tokio)?; + + subscriber + .with( + tracing_opentelemetry::layer() + .with_error_records_to_exceptions(true) + .with_tracer(tracer), + ) + .init(); + } + }; Ok(()) }