llm_optimizer_processor/telemetry/
mod.rs1pub mod context;
101pub mod metrics;
102pub mod resource;
103pub mod tracing;
104
105pub use context::{
107 extract_context, extract_from_headers, inject_context, inject_into_headers,
108 context_with_span, get_baggage, propagate_context, with_baggage, with_context,
109 BaggageItem, HeaderCarrier,
110};
111
112pub use metrics::{
113 init_meter_provider, shutdown_meter_provider, metric_attributes, metric_names,
114 ExportConfig, MetricsConfig, MetricsRecorder, Temporality,
115};
116
117pub use resource::{create_processor_resource, ResourceBuilder};
118
119pub use tracing::{
120 init_tracer_provider, record_exception, shutdown_tracer_provider, BatchConfiguration,
121 OtlpProtocol, SamplingStrategy, SpanBuilder, TraceConfig,
122};
123
124pub use opentelemetry::{
126 global,
127 trace::{Span, SpanKind, Status, Tracer},
128 Context, KeyValue,
129};
130
131#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
133pub struct TelemetryConfig {
134 pub tracing: TraceConfig,
136
137 pub metrics: MetricsConfig,
139}
140
141impl Default for TelemetryConfig {
142 fn default() -> Self {
143 Self {
144 tracing: TraceConfig::default(),
145 metrics: MetricsConfig::default(),
146 }
147 }
148}
149
150impl TelemetryConfig {
151 pub fn new(service_name: impl Into<String>) -> Self {
153 let service_name = service_name.into();
154 Self {
155 tracing: TraceConfig {
156 service_name: service_name.clone(),
157 ..Default::default()
158 },
159 metrics: MetricsConfig {
160 service_name,
161 ..Default::default()
162 },
163 }
164 }
165
166 pub fn with_otlp_endpoint(mut self, endpoint: impl Into<String>) -> Self {
168 let endpoint = endpoint.into();
169 self.tracing.otlp_endpoint = endpoint.clone();
170 self.metrics.otlp_endpoint = endpoint;
171 self
172 }
173
174 pub fn with_service_version(mut self, version: impl Into<String>) -> Self {
176 let version = version.into();
177 self.tracing.service_version = version.clone();
178 self.metrics.service_version = version;
179 self
180 }
181
182 pub fn with_environment(mut self, env: impl Into<String>) -> Self {
184 let env = Some(env.into());
185 self.tracing.environment = env.clone();
186 self.metrics.environment = env;
187 self
188 }
189
190 pub fn with_tracing_enabled(mut self, enabled: bool) -> Self {
192 self.tracing.enabled = enabled;
193 self
194 }
195
196 pub fn with_metrics_enabled(mut self, enabled: bool) -> Self {
198 self.metrics.enabled = enabled;
199 self
200 }
201}
202
203pub fn init_telemetry(
209 config: TelemetryConfig,
210) -> Result<TelemetryProviders, Box<dyn std::error::Error>> {
211 let tracer_provider = if config.tracing.enabled {
212 Some(init_tracer_provider(config.tracing)?)
213 } else {
214 None
215 };
216
217 let meter_provider = if config.metrics.enabled {
218 Some(init_meter_provider(config.metrics)?)
219 } else {
220 None
221 };
222
223 Ok(TelemetryProviders {
224 tracer_provider,
225 meter_provider,
226 })
227}
228
229pub struct TelemetryProviders {
231 pub tracer_provider: Option<opentelemetry_sdk::trace::TracerProvider>,
232 pub meter_provider: Option<opentelemetry_sdk::metrics::SdkMeterProvider>,
233}
234
235impl TelemetryProviders {
236 pub async fn shutdown(self) -> Result<(), Box<dyn std::error::Error>> {
238 if let Some(_provider) = self.tracer_provider {
239 shutdown_tracer_provider().await;
240 }
241
242 if let Some(_provider) = self.meter_provider {
243 shutdown_meter_provider()?;
244 }
245
246 Ok(())
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 #[test]
255 fn test_telemetry_config_default() {
256 let config = TelemetryConfig::default();
257 assert!(config.tracing.enabled);
258 assert!(config.metrics.enabled);
259 }
260
261 #[test]
262 fn test_telemetry_config_new() {
263 let config = TelemetryConfig::new("test-service");
264 assert_eq!(config.tracing.service_name, "test-service");
265 assert_eq!(config.metrics.service_name, "test-service");
266 }
267
268 #[test]
269 fn test_telemetry_config_builder() {
270 let config = TelemetryConfig::new("test-service")
271 .with_otlp_endpoint("http://collector:4317")
272 .with_service_version("1.0.0")
273 .with_environment("production")
274 .with_tracing_enabled(true)
275 .with_metrics_enabled(false);
276
277 assert_eq!(config.tracing.otlp_endpoint, "http://collector:4317");
278 assert_eq!(config.metrics.otlp_endpoint, "http://collector:4317");
279 assert_eq!(config.tracing.service_version, "1.0.0");
280 assert_eq!(config.metrics.service_version, "1.0.0");
281 assert_eq!(
282 config.tracing.environment,
283 Some("production".to_string())
284 );
285 assert_eq!(
286 config.metrics.environment,
287 Some("production".to_string())
288 );
289 assert!(config.tracing.enabled);
290 assert!(!config.metrics.enabled);
291 }
292
293 #[test]
294 fn test_telemetry_config_serialization() {
295 let config = TelemetryConfig::new("test");
296 let json = serde_json::to_string(&config).unwrap();
297 let deserialized: TelemetryConfig = serde_json::from_str(&json).unwrap();
298
299 assert_eq!(config.tracing.service_name, deserialized.tracing.service_name);
300 assert_eq!(config.metrics.service_name, deserialized.metrics.service_name);
301 }
302}