use opentelemetry::trace::TracerProvider;
use opentelemetry_sdk::Resource;
use opentelemetry_sdk::trace::SdkTracerProvider;
use tracing::Subscriber;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::registry::LookupSpan;
use tracing_subscriber::{EnvFilter, Layer};
use crate::Initializer;
pub(crate) fn setup_otlp_layer<S>(
initializer: &Initializer,
) -> (Option<impl Layer<S>>, FinalizeGuard)
where
S: Subscriber + for<'span> LookupSpan<'span>,
{
let log_env_var = format!("{}_LOG_OTLP", initializer.env_var_prefix);
if std::env::var_os(&log_env_var).is_some() {
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_http()
.build()
.unwrap();
let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
.with_resource(Resource::builder().build())
.with_batch_exporter(exporter)
.build();
opentelemetry::global::set_tracer_provider(provider.clone());
let tracer = provider.tracer("rust-tracing");
let filter = EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.with_env_var(&log_env_var)
.from_env_lossy();
let layer = tracing_opentelemetry::layer()
.with_tracer(tracer)
.with_filter(filter);
(
Some(layer),
FinalizeGuard {
provider: Some(provider),
},
)
} else {
(None, FinalizeGuard { provider: None })
}
}
#[derive(Debug)]
pub(crate) struct FinalizeGuard {
provider: Option<SdkTracerProvider>,
}
impl Drop for FinalizeGuard {
fn drop(&mut self) {
if let Some(provider) = &self.provider {
if let Err(error) = provider.force_flush() {
eprintln!("ERROR: Unable to flush traces via OTLP. {error}")
}
}
}
}