use std::collections::HashMap;
use std::sync::{Mutex, Once};
use opentelemetry::propagation::TextMapPropagator;
use opentelemetry_sdk::propagation::TraceContextPropagator;
use tracing_opentelemetry::OpenTelemetrySpanExt;
#[must_use]
pub fn current_trace_parent() -> Option<String> {
let context = tracing::Span::current().context();
let propagator = TraceContextPropagator::new();
let mut carrier = HashMap::new();
propagator.inject_context(&context, &mut carrier);
carrier.remove("traceparent")
}
#[must_use]
pub fn context_from_trace_parent(trace_parent: &str) -> opentelemetry::Context {
let propagator = TraceContextPropagator::new();
let mut carrier = HashMap::new();
carrier.insert("traceparent".to_string(), trace_parent.to_string());
propagator.extract(&carrier)
}
static INIT: Once = Once::new();
static PROVIDER: Mutex<Option<opentelemetry_sdk::trace::SdkTracerProvider>> = Mutex::new(None);
pub fn init_tracing(default_service_name: &str) {
let default_name = default_service_name.to_string();
INIT.call_once(move || {
use opentelemetry::trace::TracerProvider;
use opentelemetry_otlp::WithExportConfig;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
let fmt_layer = tracing_subscriber::fmt::layer().with_target(true);
let endpoint = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok();
if let Some(endpoint) = endpoint {
let service_name = std::env::var("OTEL_SERVICE_NAME").unwrap_or(default_name);
let exporter = match opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_endpoint(&endpoint)
.build()
{
Ok(e) => e,
Err(err) => {
#[allow(clippy::print_stderr)]
{
eprintln!("sayiir: failed to create OTLP exporter: {err}");
}
tracing_subscriber::registry()
.with(filter)
.with(fmt_layer)
.init();
return;
}
};
let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
.with_batch_exporter(exporter)
.with_resource(
opentelemetry_sdk::Resource::builder()
.with_service_name(service_name)
.build(),
)
.build();
let tracer = provider.tracer("sayiir");
let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
tracing_subscriber::registry()
.with(filter)
.with(fmt_layer)
.with(otel_layer)
.init();
if let Ok(mut guard) = PROVIDER.lock() {
*guard = Some(provider);
}
} else {
tracing_subscriber::registry()
.with(filter)
.with(fmt_layer)
.init();
}
});
}
pub fn shutdown_tracing() {
if let Ok(mut guard) = PROVIDER.lock()
&& let Some(provider) = guard.take()
{
let _ = provider.shutdown();
}
}