1use std::sync::{Arc, Once};
4use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
5
6use crate::span_exporter::{AdkSpanExporter, AdkSpanLayer};
7
8static INIT: Once = Once::new();
9
10#[derive(Debug, thiserror::Error)]
12pub enum TelemetryError {
13 #[error("telemetry init failed: {0}")]
15 Init(String),
16}
17
18pub fn init_telemetry(service_name: &str) -> Result<(), TelemetryError> {
29 INIT.call_once(|| {
30 let filter = EnvFilter::try_from_default_env()
31 .or_else(|_| EnvFilter::try_new("info"))
32 .expect("Failed to create env filter");
33
34 tracing_subscriber::registry()
35 .with(filter)
36 .with(
37 tracing_subscriber::fmt::layer()
38 .with_target(true)
39 .with_thread_ids(true)
40 .with_line_number(true),
41 )
42 .init();
43
44 tracing::info!(service.name = service_name, "telemetry initialized");
45 });
46
47 Ok(())
48}
49
50pub fn init_with_otlp(service_name: &str, endpoint: &str) -> Result<(), TelemetryError> {
65 use opentelemetry_otlp::WithExportConfig;
66 use tracing_opentelemetry::OpenTelemetryLayer;
67
68 INIT.call_once(|| {
69 let tracer = opentelemetry_otlp::new_pipeline()
71 .tracing()
72 .with_exporter(opentelemetry_otlp::new_exporter().tonic().with_endpoint(endpoint))
73 .with_trace_config(opentelemetry_sdk::trace::config().with_resource(
74 opentelemetry_sdk::Resource::new(vec![opentelemetry::KeyValue::new(
75 "service.name",
76 service_name.to_string(),
77 )]),
78 ))
79 .install_batch(opentelemetry_sdk::runtime::Tokio)
80 .expect("Failed to install OTLP pipeline");
81
82 let meter_provider = opentelemetry_otlp::new_pipeline()
84 .metrics(opentelemetry_sdk::runtime::Tokio)
85 .with_exporter(opentelemetry_otlp::new_exporter().tonic().with_endpoint(endpoint))
86 .with_resource(opentelemetry_sdk::Resource::new(vec![opentelemetry::KeyValue::new(
87 "service.name",
88 service_name.to_string(),
89 )]))
90 .build()
91 .expect("Failed to build meter provider");
92
93 opentelemetry::global::set_meter_provider(meter_provider);
94
95 let telemetry_layer = OpenTelemetryLayer::new(tracer);
96
97 let filter = EnvFilter::try_from_default_env()
98 .or_else(|_| EnvFilter::try_new("info"))
99 .expect("Failed to create env filter");
100
101 tracing_subscriber::registry()
102 .with(filter)
103 .with(
104 tracing_subscriber::fmt::layer()
105 .with_target(true)
106 .with_thread_ids(true)
107 .with_line_number(true),
108 )
109 .with(telemetry_layer)
110 .init();
111
112 tracing::info!(
113 service.name = service_name,
114 otlp.endpoint = endpoint,
115 "telemetry initialized with OpenTelemetry"
116 );
117 });
118
119 Ok(())
120}
121
122pub fn shutdown_telemetry() {
126 opentelemetry::global::shutdown_tracer_provider();
127}
128
129pub fn init_with_adk_exporter(service_name: &str) -> Result<Arc<AdkSpanExporter>, TelemetryError> {
134 let exporter = Arc::new(AdkSpanExporter::new());
135 let exporter_clone = exporter.clone();
136
137 INIT.call_once(|| {
138 let filter = EnvFilter::try_from_default_env()
139 .or_else(|_| EnvFilter::try_new("info"))
140 .expect("Failed to create env filter");
141
142 let adk_layer = AdkSpanLayer::new(exporter_clone);
143
144 tracing_subscriber::registry()
145 .with(filter)
146 .with(
147 tracing_subscriber::fmt::layer()
148 .with_target(true)
149 .with_thread_ids(true)
150 .with_line_number(true),
151 )
152 .with(adk_layer)
153 .init();
154
155 tracing::info!(service.name = service_name, "telemetry initialized with ADK span exporter");
156 });
157
158 Ok(exporter)
159}