use opentelemetry::trace::TracerProvider;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::trace::SdkTracerProvider;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
pub fn init() -> Option<SdkTracerProvider> {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into());
let plain = tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::layer());
let Some(endpoint) = std::env::var("LFSX_OTLP_ENDPOINT")
.ok()
.filter(|endpoint| !endpoint.is_empty())
else {
plain.init();
return None;
};
let exporter = match opentelemetry_otlp::SpanExporter::builder()
.with_http()
.with_endpoint(&endpoint)
.build()
{
Ok(exporter) => exporter,
Err(error) => {
plain.init();
tracing::error!(
%error,
endpoint,
"LFSX_OTLP_ENDPOINT is set but no exporter could be built for it, so traces are off"
);
return None;
}
};
opentelemetry::global::set_text_map_propagator(
opentelemetry_sdk::propagation::TraceContextPropagator::new(),
);
let provider = SdkTracerProvider::builder()
.with_batch_exporter(exporter)
.with_resource(
opentelemetry_sdk::Resource::builder()
.with_service_name("lfsx")
.build(),
)
.build();
plain
.with(tracing_opentelemetry::layer().with_tracer(provider.tracer("lfsx")))
.init();
tracing::info!(endpoint, "traces are exported over OTLP");
Some(provider)
}
pub(crate) fn propagated(request: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
use tracing_opentelemetry::OpenTelemetrySpanExt;
let context = tracing::Span::current().context();
let mut carrier = std::collections::HashMap::new();
opentelemetry::global::get_text_map_propagator(|propagator| {
propagator.inject_context(&context, &mut carrier);
});
carrier.into_iter().fold(request, |request, (name, value)| {
request.header(name, value)
})
}