#![cfg(all(feature = "otlp", not(target_arch = "wasm32")))]
use csm_core_lib::error::{MemoryError, Result};
use opentelemetry::KeyValue;
use opentelemetry::trace::TracerProvider as _;
use opentelemetry_otlp::SpanExporter;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::resource::Resource;
use opentelemetry_sdk::trace::TracerProvider;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
pub struct OtlpGuard {
provider: Option<TracerProvider>,
}
impl OtlpGuard {
pub fn empty() -> Self {
Self { provider: None }
}
pub fn shutdown(&mut self) {
if let Some(provider) = self.provider.take() {
let _ = provider.shutdown();
}
}
}
impl Drop for OtlpGuard {
fn drop(&mut self) {
self.shutdown();
}
}
pub fn install_grpc_tracer(endpoint: &str, service_name: &str) -> Result<OtlpGuard> {
let exporter = SpanExporter::builder()
.with_tonic()
.with_endpoint(endpoint)
.build()
.map_err(|e| MemoryError::Observability(format!("OTLP gRPC exporter build: {e}")))?;
let resource = Resource::new(vec![KeyValue::new(
"service.name",
service_name.to_string(),
)]);
let provider = TracerProvider::builder()
.with_simple_exporter(exporter)
.with_resource(resource)
.build();
let tracer = provider.tracer("csm-otlp");
opentelemetry::global::set_tracer_provider(provider.clone());
let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let _ = tracing_subscriber::registry().with(otel_layer).try_init();
Ok(OtlpGuard {
provider: Some(provider),
})
}