use opentelemetry::{global, trace::TracerProvider as _, KeyValue}; use opentelemetry_sdk::{ metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider}, runtime, trace::{RandomIdGenerator, Sampler, Tracer, TracerProvider}, Resource, }; use opentelemetry_semantic_conventions::{ attribute::{DEPLOYMENT_ENVIRONMENT_NAME, SERVICE_NAME, SERVICE_VERSION}, SCHEMA_URL, }; use tracing_core::Level; use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; // Create a Resource that captures information about the entity for which telemetry is recorded. fn resource() -> Resource { Resource::from_schema_url( [ KeyValue::new(SERVICE_NAME, env!("CARGO_PKG_NAME")), KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")), KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, "develop"), ], SCHEMA_URL, ) } // Construct MeterProvider for MetricsLayer fn init_meter_provider() -> SdkMeterProvider { let exporter = opentelemetry_otlp::MetricExporter::builder() .with_tonic() .with_temporality(opentelemetry_sdk::metrics::Temporality::default()) .build() .unwrap(); let reader = PeriodicReader::builder(exporter, runtime::Tokio) .with_interval(std::time::Duration::from_secs(30)) .build(); // For debugging in development let stdout_reader = PeriodicReader::builder( opentelemetry_stdout::MetricExporter::default(), runtime::Tokio, ) .build(); let meter_provider = MeterProviderBuilder::default() .with_resource(resource()) .with_reader(reader) .with_reader(stdout_reader) .build(); global::set_meter_provider(meter_provider.clone()); meter_provider } // Construct Tracer for OpenTelemetryLayer fn init_tracer() -> Tracer { let exporter = opentelemetry_otlp::SpanExporter::builder() .with_tonic() .build() .unwrap(); let provider = TracerProvider::builder() .with_config( opentelemetry_sdk::trace::Config::default() // Customize sampling strategy .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased( 1.0, )))) // If export trace to AWS X-Ray, you can use XrayIdGenerator .with_id_generator(RandomIdGenerator::default()) .with_resource(resource()), ) .with_batch_exporter(exporter, runtime::Tokio) .build(); global::set_tracer_provider(provider.clone()); provider.tracer("tracing-otel-subscriber") } // Initialize tracing-subscriber and return OtelGuard for opentelemetry-related termination processing fn init_tracing_subscriber() -> OtelGuard { let meter_provider = init_meter_provider(); let tracer = init_tracer(); tracing_subscriber::registry() .with(tracing_subscriber::filter::LevelFilter::from_level( Level::INFO, )) .with(tracing_subscriber::fmt::layer()) .with(MetricsLayer::new(meter_provider.clone())) .with(OpenTelemetryLayer::new(tracer)) .init(); OtelGuard { meter_provider } } struct OtelGuard { meter_provider: SdkMeterProvider, } impl Drop for OtelGuard { fn drop(&mut self) { if let Err(err) = self.meter_provider.shutdown() { eprintln!("{err:?}"); } opentelemetry::global::shutdown_tracer_provider(); } } #[tokio::main] async fn main() { let _guard = init_tracing_subscriber(); foo().await; } #[tracing::instrument] async fn foo() { tracing::info!( monotonic_counter.foo = 1_u64, key_1 = "bar", key_2 = 10, "handle foo", ); tracing::info!(histogram.baz = 10, "histogram example",); }