diff --git a/Cargo.lock b/Cargo.lock index e0600fc..b9743f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,6 +275,8 @@ version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -360,6 +362,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -375,6 +387,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-channel" version = "0.5.14" @@ -565,6 +586,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1121,6 +1152,7 @@ dependencies = [ "opentelemetry-otlp", "opentelemetry-semantic-conventions", "opentelemetry_sdk", + "tonic", "tracing-opentelemetry", "tracing-subscriber", ] @@ -1163,6 +1195,15 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.76" @@ -1305,7 +1346,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -1987,6 +2028,7 @@ version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ + "log", "once_cell", "ring", "rustls-pki-types", @@ -1995,6 +2037,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.0.1", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -2084,7 +2138,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" +dependencies = [ + "bitflags", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -2385,7 +2452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -2676,6 +2743,7 @@ dependencies = [ "axum", "base64", "bytes", + "flate2", "h2", "http", "http-body", @@ -2686,13 +2754,17 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-native-certs", + "rustls-pemfile", "socket2", "tokio", + "tokio-rustls 0.26.1", "tokio-stream", "tower 0.4.13", "tower-layer", "tower-service", "tracing", + "zstd", ] [[package]] @@ -3383,3 +3455,31 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index a844188..563c47d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ http = "1.2.0" once_cell = "1.20.2" opentelemetry = "0.27.1" opentelemetry-appender-tracing = { version = "0.27.0", features = ["log", "experimental_metadata_attributes"] } -opentelemetry-otlp = { version = "0.27.0", features = ["grpc-tonic", "trace"] } +opentelemetry-otlp = { version = "0.27.0", features = ["grpc-tonic", "gzip-tonic", "zstd-tonic", "tls", "tls-roots", "trace"] } opentelemetry_sdk = { version = "0.27.1", features = ["metrics", "rt-tokio"] } opentelemetry-semantic-conventions = "0.27.0" opentelemetry-stdout = "0.27.0" @@ -47,6 +47,7 @@ serde = { version = "1.0.216", features = ["derive"] } slog = "2.7.0" slog-async = "2.8.0" tokio = { version = "1.42.0", features = ["full"] } +tonic = "0.12.3" tracing = "0.1.41" tracing-core = "0.1.33" tracing-chrome = "0.7.2" diff --git a/controller/src/bin/patagia-controller.rs b/controller/src/bin/patagia-controller.rs index faa1eef..640390d 100644 --- a/controller/src/bin/patagia-controller.rs +++ b/controller/src/bin/patagia-controller.rs @@ -14,12 +14,15 @@ use patagia_controller::context::ControllerContext; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] -struct Cli {} +struct Cli { + #[arg(long = "telemetry-otlp-endpoint", default_value = "http://localhost:4317", value_name = "OTEL_EXPORTER_OTLP_ENDPOINT")] + otlp_endpoint: Option, +} #[tokio::main] async fn main() -> Result<()> { - let _args = Cli::parse(); - let _tracing = instrumentation::init_tracing_subscriber()?; + let args = Cli::parse(); + let _tracing = instrumentation::init_tracing(args.otlp_endpoint.as_ref())?; tracing::info!("Patagia Controller"); diff --git a/controller/src/version.rs b/controller/src/version.rs index 47ae784..4936741 100644 --- a/controller/src/version.rs +++ b/controller/src/version.rs @@ -30,6 +30,8 @@ pub(crate) async fn version( tracing::info_span!("Hello, span!"); + tracing::info!(monotonic_counter.version_calls = 1); + async move { tracing::info!("Someone made a request to /version"); tokio::time::sleep(std::time::Duration::from_millis(200)).await; diff --git a/instrumentation/Cargo.toml b/instrumentation/Cargo.toml index 8d46c39..57edfd5 100644 --- a/instrumentation/Cargo.toml +++ b/instrumentation/Cargo.toml @@ -12,5 +12,6 @@ opentelemetry-otlp.workspace = true opentelemetry_sdk.workspace = true opentelemetry-semantic-conventions.workspace = true opentelemetry.workspace = true +tonic.workspace = true tracing-opentelemetry.workspace = true tracing-subscriber.workspace = true diff --git a/instrumentation/src/instrumentation.rs b/instrumentation/src/instrumentation.rs deleted file mode 100644 index 360a539..0000000 --- a/instrumentation/src/instrumentation.rs +++ /dev/null @@ -1,102 +0,0 @@ -use anyhow::{anyhow, Result}; -use once_cell::sync::Lazy; -use opentelemetry::{trace::TracerProvider as _, KeyValue}; -use opentelemetry_sdk::{ - metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider}, - runtime, - trace::{RandomIdGenerator, Sampler, TracerProvider}, - Resource, -}; -use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer}; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; - -static RESOURCE: Lazy = Lazy::new(|| { - Resource::new(vec![ - KeyValue::new( - opentelemetry_semantic_conventions::resource::SERVICE_NAME, - env!("CARGO_PKG_NAME"), - ), - KeyValue::new( - opentelemetry_semantic_conventions::resource::SERVICE_VERSION, - env!("CARGO_PKG_VERSION"), - ), - ]) -}); - -// Construct MeterProvider for MetricsLayer -fn init_meter_provider() -> Result { - let exporter = opentelemetry_otlp::MetricExporter::builder() - .with_tonic() - .with_temporality(opentelemetry_sdk::metrics::Temporality::default()) - .build() - .map_err(|e| anyhow!("Error creating OTLP metric exporter: {:?}", e))?; - - let meter_provider = MeterProviderBuilder::default() - .with_resource(RESOURCE.clone()) - .with_reader( - PeriodicReader::builder(exporter, runtime::Tokio) - .with_interval(std::time::Duration::from_secs(10)) - .build(), - ) - .build(); - - opentelemetry::global::set_meter_provider(meter_provider.clone()); - - Ok(meter_provider) -} - -// Construct TracerProvider for OpenTelemetryLayer -fn init_tracer_provider() -> Result { - let exporter = opentelemetry_otlp::SpanExporter::builder() - .with_tonic() - .build() - .map_err(|e| anyhow!("Error creating OTLP span exporter: {:?}", e))?; - - let tracer_provider = opentelemetry_sdk::trace::TracerProvider::builder() - .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased( - 1.0, - )))) - .with_resource(RESOURCE.clone()) - .with_id_generator(RandomIdGenerator::default()) - .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio) - .build(); - - Ok(tracer_provider) -} - -// Initialize tracing-subscriber and return OtelGuard for opentelemetry-related termination processing -pub fn init_tracing_subscriber() -> Result { - let meter_provider = init_meter_provider()?; - let tracer_provider = init_tracer_provider()?; - - let tracer = tracer_provider.tracer("tracing-otel-subscriber"); - - tracing_subscriber::registry() - .with(tracing_subscriber::EnvFilter::from_default_env()) - .with(tracing_subscriber::fmt::layer()) - .with(MetricsLayer::new(meter_provider.clone())) - .with(OpenTelemetryLayer::new(tracer)) - .init(); - - Ok(OtelGuard { - meter_provider, - tracer_provider, - }) -} - -pub struct OtelGuard { - meter_provider: SdkMeterProvider, - tracer_provider: TracerProvider, -} - -impl Drop for OtelGuard { - fn drop(&mut self) { - if let Err(err) = self.tracer_provider.shutdown() { - eprintln!("{err:?}"); - } - if let Err(err) = self.meter_provider.shutdown() { - eprintln!("{err:?}"); - } - } -} diff --git a/instrumentation/src/lib.rs b/instrumentation/src/lib.rs index 360a539..b05e0fc 100644 --- a/instrumentation/src/lib.rs +++ b/instrumentation/src/lib.rs @@ -1,6 +1,7 @@ use anyhow::{anyhow, Result}; use once_cell::sync::Lazy; use opentelemetry::{trace::TracerProvider as _, KeyValue}; +use opentelemetry_otlp::{WithExportConfig, WithTonicConfig}; use opentelemetry_sdk::{ metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider}, runtime, @@ -25,9 +26,12 @@ static RESOURCE: Lazy = Lazy::new(|| { }); // Construct MeterProvider for MetricsLayer -fn init_meter_provider() -> Result { +fn init_meter_provider(otel_endpoint: &String) -> Result { let exporter = opentelemetry_otlp::MetricExporter::builder() .with_tonic() + .with_endpoint(otel_endpoint) + .with_tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots()) + .with_compression(opentelemetry_otlp::Compression::Gzip) .with_temporality(opentelemetry_sdk::metrics::Temporality::default()) .build() .map_err(|e| anyhow!("Error creating OTLP metric exporter: {:?}", e))?; @@ -47,9 +51,12 @@ fn init_meter_provider() -> Result { } // Construct TracerProvider for OpenTelemetryLayer -fn init_tracer_provider() -> Result { +fn init_tracer_provider(otel_endpoint: &String) -> Result { let exporter = opentelemetry_otlp::SpanExporter::builder() .with_tonic() + .with_tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots()) + .with_compression(opentelemetry_otlp::Compression::Gzip) + .with_endpoint(otel_endpoint) .build() .map_err(|e| anyhow!("Error creating OTLP span exporter: {:?}", e))?; @@ -65,38 +72,61 @@ fn init_tracer_provider() -> Result { Ok(tracer_provider) } -// Initialize tracing-subscriber and return OtelGuard for opentelemetry-related termination processing -pub fn init_tracing_subscriber() -> Result { - let meter_provider = init_meter_provider()?; - let tracer_provider = init_tracer_provider()?; - - let tracer = tracer_provider.tracer("tracing-otel-subscriber"); - - tracing_subscriber::registry() +// Initialize tracing-subscriber and return TracingGuard for opentelemetry-related termination processing +pub fn init_tracing(otel_endpoint: Option<&String>) -> Result { + let sub = tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::from_default_env()) - .with(tracing_subscriber::fmt::layer()) - .with(MetricsLayer::new(meter_provider.clone())) - .with(OpenTelemetryLayer::new(tracer)) - .init(); + .with(tracing_subscriber::fmt::layer()); - Ok(OtelGuard { - meter_provider, - tracer_provider, - }) -} - -pub struct OtelGuard { - meter_provider: SdkMeterProvider, - tracer_provider: TracerProvider, -} - -impl Drop for OtelGuard { - fn drop(&mut self) { - if let Err(err) = self.tracer_provider.shutdown() { - eprintln!("{err:?}"); + match otel_endpoint { + None => { + sub.init(); + Ok(TracingGuard { + meter_provider: None, + tracer_provider: None, + }) } - if let Err(err) = self.meter_provider.shutdown() { - eprintln!("{err:?}"); + + Some(otel_endpoint) => { + let meter_provider = init_meter_provider(otel_endpoint)?; + let tracer_provider = init_tracer_provider(otel_endpoint)?; + let tracer = tracer_provider.tracer("tracing-otel-subscriber"); + sub.with(MetricsLayer::new(meter_provider.clone())) + .with(OpenTelemetryLayer::new(tracer)) + .init(); + Ok(TracingGuard { + meter_provider: Some(meter_provider), + tracer_provider: Some(tracer_provider), + }) + } + } +} + +pub struct TracingGuard { + meter_provider: Option, + tracer_provider: Option, +} + +impl Drop for TracingGuard { + fn drop(&mut self) { + if let Some(tracer_provider) = &self.tracer_provider { + for result in tracer_provider.force_flush() { + if let Err(err) = result { + eprintln!("{err:?}"); + } + } + if let Err(err) = tracer_provider.shutdown() { + eprintln!("{err:?}"); + } + } + + if let Some(meter_provider) = &self.meter_provider { + if let Err(err) = meter_provider.force_flush() { + eprintln!("{err:?}"); + } + if let Err(err) = meter_provider.shutdown() { + eprintln!("{err:?}"); + } } } }