#[cfg(feature = "otel")]
use opentelemetry::trace::TracerProvider as _;
#[cfg(feature = "otel")]
use opentelemetry::KeyValue;
#[cfg(feature = "otel")]
use opentelemetry_sdk::runtime::Tokio;
#[cfg(feature = "otel")]
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
#[cfg(feature = "otel")]
pub struct TracingGuard {
_provider: opentelemetry_sdk::trace::TracerProvider,
}
#[cfg(feature = "otel")]
impl Drop for TracingGuard {
fn drop(&mut self) {
if let Err(e) = self._provider.shutdown() {
eprintln!("otel shutdown error: {e}");
}
}
}
#[cfg(feature = "otel")]
pub fn init_tracing(
service_name: &str,
default_filter: &str,
) -> Result<TracingGuard, Box<dyn std::error::Error>> {
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.build()?;
let provider = opentelemetry_sdk::trace::TracerProvider::builder()
.with_batch_exporter(exporter, Tokio)
.with_resource(opentelemetry_sdk::Resource::new(vec![KeyValue::new(
"service.name",
service_name.to_string(),
)]))
.build();
let tracer = provider.tracer(service_name.to_string());
let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let filter =
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(default_filter));
let fmt_layer = tracing_subscriber::fmt::layer()
.json()
.with_target(true)
.with_span_list(true);
tracing_subscriber::registry()
.with(filter)
.with(fmt_layer)
.with(otel_layer)
.init();
Ok(TracingGuard {
_provider: provider,
})
}