1use opentelemetry::trace::TracerProvider;
2use opentelemetry_otlp::WithExportConfig;
3use opentelemetry_sdk::trace::SdkTracerProvider;
4use tracing_subscriber::EnvFilter;
5use tracing_subscriber::layer::SubscriberExt;
6use tracing_subscriber::util::SubscriberInitExt;
7
8pub fn init() -> Option<SdkTracerProvider> {
17 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into());
18 let plain = tracing_subscriber::registry()
19 .with(filter)
20 .with(tracing_subscriber::fmt::layer());
21
22 let Some(endpoint) = std::env::var("LFSX_OTLP_ENDPOINT")
23 .ok()
24 .filter(|endpoint| !endpoint.is_empty())
25 else {
26 plain.init();
27 return None;
28 };
29
30 let exporter = match opentelemetry_otlp::SpanExporter::builder()
31 .with_http()
32 .with_endpoint(&endpoint)
33 .build()
34 {
35 Ok(exporter) => exporter,
36 Err(error) => {
37 plain.init();
38 tracing::error!(
39 %error,
40 endpoint,
41 "LFSX_OTLP_ENDPOINT is set but no exporter could be built for it, so traces are off"
42 );
43 return None;
44 }
45 };
46
47 opentelemetry::global::set_text_map_propagator(
48 opentelemetry_sdk::propagation::TraceContextPropagator::new(),
49 );
50
51 let provider = SdkTracerProvider::builder()
52 .with_batch_exporter(exporter)
53 .with_resource(
54 opentelemetry_sdk::Resource::builder()
55 .with_service_name("lfsx")
56 .build(),
57 )
58 .build();
59
60 plain
61 .with(tracing_opentelemetry::layer().with_tracer(provider.tracer("lfsx")))
62 .init();
63 tracing::info!(endpoint, "traces are exported over OTLP");
64
65 Some(provider)
66}
67
68pub(crate) fn propagated(request: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
72 use tracing_opentelemetry::OpenTelemetrySpanExt;
73
74 let context = tracing::Span::current().context();
75 let mut carrier = std::collections::HashMap::new();
76 opentelemetry::global::get_text_map_propagator(|propagator| {
77 propagator.inject_context(&context, &mut carrier);
78 });
79
80 carrier.into_iter().fold(request, |request, (name, value)| {
81 request.header(name, value)
82 })
83}