1use tracing_subscriber::{fmt::format::FmtSpan, layer::SubscriberExt, util::SubscriberInitExt};
2
3pub fn init_trace(crate_name: &str) {
5 tracing_subscriber::registry()
6 .with(
7 tracing_subscriber::EnvFilter::try_from_default_env()
8 .unwrap_or_else(|_| format!("{}=debug,tower_http=debug", crate_name).into()),
9 )
10 .with(tracing_subscriber::fmt::layer().with_span_events(FmtSpan::CLOSE))
11 .init();
12}
13
14#[cfg(feature = "otlp")]
18pub fn init_trace_with_otlp(crate_name: &str, otlp_endpoint: &str, service_name: &str) {
19 use opentelemetry::trace::TracerProvider;
20 use opentelemetry_otlp::WithExportConfig;
21 use opentelemetry_sdk::trace::SdkTracerProvider;
22
23 let exporter = match opentelemetry_otlp::SpanExporter::builder()
24 .with_tonic()
25 .with_endpoint(otlp_endpoint)
26 .build()
27 {
28 Ok(e) => e,
29 Err(err) => {
30 eprintln!("Failed to create OTLP exporter: {err} — falling back to fmt-only tracing");
31 init_trace(crate_name);
32 return;
33 }
34 };
35
36 let provider = SdkTracerProvider::builder()
37 .with_batch_exporter(exporter)
38 .with_resource(
39 opentelemetry_sdk::Resource::builder()
40 .with_service_name(service_name.to_string())
41 .build(),
42 )
43 .build();
44
45 let tracer = provider.tracer(service_name.to_string());
46
47 PROVIDER.set(provider).ok();
49
50 let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
51
52 tracing_subscriber::registry()
53 .with(
54 tracing_subscriber::EnvFilter::try_from_default_env()
55 .unwrap_or_else(|_| format!("{}=debug,tower_http=debug", crate_name).into()),
56 )
57 .with(tracing_subscriber::fmt::layer().with_span_events(FmtSpan::CLOSE))
58 .with(otel_layer)
59 .init();
60}
61
62#[cfg(feature = "otlp")]
63static PROVIDER: std::sync::OnceLock<opentelemetry_sdk::trace::SdkTracerProvider> =
64 std::sync::OnceLock::new();
65
66#[cfg(feature = "otlp")]
68pub fn shutdown_trace() {
69 if let Some(provider) = PROVIDER.get() {
70 let _ = provider.shutdown();
71 }
72}
73
74#[cfg(not(feature = "otlp"))]
76pub fn shutdown_trace() {}