use opentelemetry::global; use opentelemetry_sdk::logs::SdkLoggerProvider; use opentelemetry_sdk::metrics::SdkMeterProvider; use opentelemetry_sdk::trace::SdkTracerProvider; use super::config::TelemetryConfig; use super::error::TelemetryError; use super::{logs, metrics, propagation, resource, subscriber, traces}; #[derive(Debug, Clone)] pub struct Telemetry { tracer_provider: SdkTracerProvider, meter_provider: SdkMeterProvider, logger_provider: SdkLoggerProvider, warnings: Vec, } impl Telemetry { pub fn tracer_provider(&self) -> &SdkTracerProvider { &self.tracer_provider } pub fn meter_provider(&self) -> &SdkMeterProvider { &self.meter_provider } pub fn logger_provider(&self) -> &SdkLoggerProvider { &self.logger_provider } pub fn warnings(&self) -> &[String] { &self.warnings } pub fn force_flush(&self) -> Result<(), TelemetryError> { first_error([ self.tracer_provider .force_flush() .map_err(TelemetryError::exporter), self.meter_provider .force_flush() .map_err(TelemetryError::exporter), self.logger_provider .force_flush() .map_err(TelemetryError::exporter), ]) } pub fn shutdown(&self) -> Result<(), TelemetryError> { first_error([ self.tracer_provider .shutdown() .map_err(TelemetryError::shutdown), self.meter_provider .shutdown() .map_err(TelemetryError::shutdown), self.logger_provider .shutdown() .map_err(TelemetryError::shutdown), ]) } pub fn guard(&self) -> TelemetryGuard<'_> { TelemetryGuard { telemetry: self } } } pub struct TelemetryGuard<'a> { telemetry: &'a Telemetry, } impl Drop for TelemetryGuard<'_> { fn drop(&mut self) { if let Err(error) = self.telemetry.shutdown() { tracing::warn!(%error, "flushing telemetry failed"); } } } fn first_error(errors: [Result<(), TelemetryError>; 3]) -> Result<(), TelemetryError> { match errors.into_iter().find(Result::is_err) { Some(error) => error, None => Ok(()), } } pub fn install(config: &TelemetryConfig) -> Telemetry { let resource = resource::build(config); let mut warnings = Vec::new(); let tracer_provider = traces::build(config, resource.clone(), &mut warnings); let meter_provider = metrics::build(config, resource.clone(), &mut warnings); let logger_provider = logs::build(config, resource, &mut warnings); global::set_tracer_provider(tracer_provider.clone()); global::set_meter_provider(meter_provider.clone()); propagation::install(); Telemetry { tracer_provider, meter_provider, logger_provider, warnings, } } pub fn init(config: &TelemetryConfig) -> Telemetry { let telemetry = install(config); subscriber::install(config, &telemetry); telemetry }