1use mem7_config::TelemetryConfig;
2use mem7_error::Result;
3use opentelemetry::trace::TracerProvider as _;
4use opentelemetry_otlp::{SpanExporter, WithExportConfig};
5use opentelemetry_sdk::{Resource, trace::SdkTracerProvider};
6use tracing_opentelemetry::OpenTelemetryLayer;
7use tracing_subscriber::{
8 EnvFilter, Layer, Registry, layer::SubscriberExt, util::SubscriberInitExt,
9};
10
11static PROVIDER: std::sync::OnceLock<SdkTracerProvider> = std::sync::OnceLock::new();
12
13pub fn init(config: &TelemetryConfig) -> Result<()> {
21 let exporter = SpanExporter::builder()
22 .with_tonic()
23 .with_endpoint(&config.otlp_endpoint)
24 .build()
25 .map_err(|e| mem7_error::Mem7Error::Config(format!("OTLP exporter: {e}")))?;
26
27 let resource = Resource::builder()
28 .with_service_name(config.service_name.clone())
29 .build();
30
31 let provider = SdkTracerProvider::builder()
32 .with_resource(resource)
33 .with_batch_exporter(exporter)
34 .build();
35
36 let tracer = provider.tracer("mem7");
37
38 PROVIDER
39 .set(provider)
40 .map_err(|_| mem7_error::Mem7Error::Config("telemetry already initialized".into()))?;
41
42 let otel_layer = OpenTelemetryLayer::new(tracer);
43
44 let fmt_layer = tracing_subscriber::fmt::layer()
45 .with_target(true)
46 .with_level(true)
47 .with_filter(EnvFilter::from_default_env());
48
49 Registry::default().with(fmt_layer).with(otel_layer).init();
50
51 Ok(())
52}
53
54pub fn shutdown() {
56 if let Some(provider) = PROVIDER.get()
57 && let Err(e) = provider.shutdown()
58 {
59 tracing::warn!(error = %e, "failed to shutdown telemetry provider");
60 }
61}