use std::sync::OnceLock;
use opentelemetry::{KeyValue, global, trace::TracerProvider as _};
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::{
Resource, propagation::TraceContextPropagator, runtime, trace::TracerProvider,
};
use opentelemetry_semantic_conventions::resource::SERVICE_NAME;
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
pub mod capability_metrics;
pub mod propagate;
pub use propagate::{
extract_context_from_map, inject_current_context, inject_current_context_http,
inject_current_context_map,
};
static INITIALIZED: OnceLock<()> = OnceLock::new();
const DEFAULT_ENDPOINT: &str = "http://otel-collector.observability.svc.cluster.local:4317";
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("otlp exporter init failed: {0}")]
Exporter(#[from] opentelemetry::trace::TraceError),
}
pub fn init(service_name: &str) -> Result<(), Error> {
if std::env::var("TONIN_TELEMETRY").as_deref() == Ok("off") {
let _ = INITIALIZED.set(());
let _ = tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
)
.try_init();
return Ok(());
}
if INITIALIZED.get().is_some() {
return Ok(());
}
global::set_text_map_propagator(TraceContextPropagator::new());
let endpoint = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT")
.unwrap_or_else(|_| DEFAULT_ENDPOINT.to_string());
let name = std::env::var("OTEL_SERVICE_NAME").unwrap_or_else(|_| service_name.to_string());
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_endpoint(endpoint)
.build()?;
let resource = Resource::new(vec![KeyValue::new(SERVICE_NAME, name.clone())]);
let provider = TracerProvider::builder()
.with_batch_exporter(exporter, runtime::Tokio)
.with_resource(resource)
.build();
let tracer = provider.tracer(name);
global::set_tracer_provider(provider);
let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let fmt_layer = tracing_subscriber::fmt::layer().with_target(false);
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::registry()
.with(env_filter)
.with(fmt_layer)
.with(otel_layer)
.try_init()
.ok();
let _ = INITIALIZED.set(());
Ok(())
}
pub fn shutdown() {
global::shutdown_tracer_provider();
}