//! OpenTelemetry distributed tracing — OTLP exporter + tracing-opentelemetry bridge. use opentelemetry::trace::TracerProvider as _; use opentelemetry_otlp::{Protocol, SpanExporter, WithExportConfig}; use opentelemetry_sdk::propagation::TraceContextPropagator; use opentelemetry_sdk::trace::{SdkTracerProvider, Tracer}; use opentelemetry_sdk::Resource; use tracing_opentelemetry::OpenTelemetryLayer; use tracing_subscriber::Registry; use super::config::{OtlpProtocol, TelemetryConfig}; use crate::ImksResult; /// Build an OTLP SpanExporter based on the configured protocol. fn build_span_exporter(config: &TelemetryConfig) -> ImksResult { match config.otlp_protocol { OtlpProtocol::Grpc => SpanExporter::builder() .with_tonic() .with_endpoint(&config.otlp_endpoint) .build() .map_err(|e| crate::ImksError::Internal(format!("OTLP gRPC span exporter: {e}"))), OtlpProtocol::HttpProtobuf => SpanExporter::builder() .with_http() .with_protocol(Protocol::HttpBinary) .with_endpoint(&config.otlp_endpoint) .build() .map_err(|e| { crate::ImksError::Internal(format!("OTLP HTTP span exporter: {e}")) }), } } /// Initialize the tracing pipeline: OTel tracer provider + tracing-opentelemetry layer. /// /// Returns (SdkTracerProvider, OpenTelemetryLayer). pub fn init_tracing( config: &TelemetryConfig, resource: &Resource, ) -> ImksResult<(SdkTracerProvider, OpenTelemetryLayer)> { // Set global propagator for W3C TraceContext extraction/injection opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new()); let exporter = build_span_exporter(config)?; let provider = SdkTracerProvider::builder() .with_resource(resource.clone()) .with_batch_exporter(exporter) .build(); let tracer = provider.tracer("imks"); let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer); Ok((provider, otel_layer)) }