use opentelemetry::trace::TracerProvider;
use opentelemetry_otlp::SpanExporter;
use opentelemetry_sdk::trace::SdkTracerProvider;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;
#[derive(Debug, Clone)]
pub struct OtelConfig {
pub endpoint: String,
pub service_name: String,
pub with_fmt_layer: bool,
}
impl Default for OtelConfig {
fn default() -> Self {
Self {
endpoint: "http://localhost:4318".to_string(),
service_name: "daimon-agent".to_string(),
with_fmt_layer: true,
}
}
}
impl OtelConfig {
pub fn endpoint(mut self, endpoint: impl Into<String>) -> Self {
self.endpoint = endpoint.into();
self
}
pub fn service_name(mut self, name: impl Into<String>) -> Self {
self.service_name = name.into();
self
}
pub fn with_fmt_layer(mut self, enabled: bool) -> Self {
self.with_fmt_layer = enabled;
self
}
}
pub struct OtelGuard {
provider: SdkTracerProvider,
}
impl OtelGuard {
pub fn shutdown(self) {
if let Err(e) = self.provider.shutdown() {
eprintln!("OpenTelemetry shutdown error: {e}");
}
}
}
pub fn init_otel_tracing(config: OtelConfig) -> Result<OtelGuard, Box<dyn std::error::Error>> {
let exporter = SpanExporter::builder()
.with_http()
.build()?;
let resource = opentelemetry_sdk::Resource::builder()
.with_service_name(config.service_name)
.build();
let provider = SdkTracerProvider::builder()
.with_batch_exporter(exporter)
.with_resource(resource)
.build();
let tracer = provider.tracer("daimon");
let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
if config.with_fmt_layer {
let fmt_layer = tracing_subscriber::fmt::layer().compact();
tracing_subscriber::registry()
.with(otel_layer)
.with(fmt_layer)
.with(filter)
.init();
} else {
tracing_subscriber::registry()
.with(otel_layer)
.with(filter)
.init();
}
Ok(OtelGuard { provider })
}