mockforge_observability/
tracing_integration.rs

1//! OpenTelemetry tracing integration for structured logging
2//!
3//! This module provides integration between the logging system and OpenTelemetry distributed tracing.
4//! It allows logs to be correlated with traces for better observability in distributed systems.
5
6use crate::logging::LoggingConfig;
7
8/// OpenTelemetry tracing configuration
9#[derive(Debug, Clone)]
10pub struct OtelTracingConfig {
11    /// Service name for traces
12    pub service_name: String,
13    /// Deployment environment (development, staging, production)
14    pub environment: String,
15    /// Jaeger endpoint for trace export
16    pub jaeger_endpoint: Option<String>,
17    /// OTLP endpoint (alternative to Jaeger)
18    pub otlp_endpoint: Option<String>,
19    /// Protocol: grpc or http
20    pub protocol: String,
21    /// Sampling rate (0.0 to 1.0)
22    pub sampling_rate: f64,
23}
24
25impl Default for OtelTracingConfig {
26    fn default() -> Self {
27        Self {
28            service_name: "mockforge".to_string(),
29            environment: "development".to_string(),
30            jaeger_endpoint: Some("http://localhost:14268/api/traces".to_string()),
31            otlp_endpoint: Some("http://localhost:4317".to_string()),
32            protocol: "grpc".to_string(),
33            sampling_rate: 1.0,
34        }
35    }
36}
37
38/// Initialize logging with OpenTelemetry tracing
39///
40/// This is a convenience function that integrates logging with OpenTelemetry when the
41/// mockforge-tracing crate is available. It initializes the OpenTelemetry tracer and
42/// sets up the logging system with a tracing layer.
43///
44/// # Arguments
45/// * `logging_config` - Logging configuration
46/// * `tracing_config` - OpenTelemetry tracing configuration
47///
48/// # Example
49/// ```no_run
50/// use mockforge_observability::tracing_integration::{init_with_otel, OtelTracingConfig};
51/// use mockforge_observability::logging::LoggingConfig;
52///
53/// let logging_config = LoggingConfig {
54///     level: "info".to_string(),
55///     json_format: true,
56///     ..Default::default()
57/// };
58///
59/// let tracing_config = OtelTracingConfig {
60///     service_name: "mockforge".to_string(),
61///     environment: "production".to_string(),
62///     ..Default::default()
63/// };
64///
65/// // init_with_otel(logging_config, tracing_config)
66/// //     .expect("Failed to initialize logging with OpenTelemetry");
67/// ```
68#[cfg(feature = "opentelemetry")]
69pub fn init_with_otel(
70    logging_config: LoggingConfig,
71    _tracing_config: OtelTracingConfig,
72) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
73    // Initialize the OpenTelemetry tracer using mockforge-tracing
74    // This would require mockforge-tracing as a dependency
75    // For now, we'll just use the logging config without OpenTelemetry
76
77    tracing::warn!("OpenTelemetry integration requires mockforge-tracing crate");
78    crate::logging::init_logging(logging_config)?;
79
80    Ok(())
81}
82
83/// Shutdown OpenTelemetry tracer and flush pending spans
84#[cfg(feature = "opentelemetry")]
85pub fn shutdown_otel() {
86    // This would call mockforge_tracing::shutdown_tracer()
87    tracing::info!("Shutting down OpenTelemetry tracer");
88}
89
90#[cfg(not(feature = "opentelemetry"))]
91pub fn init_with_otel(
92    logging_config: LoggingConfig,
93    _tracing_config: OtelTracingConfig,
94) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
95    tracing::warn!("OpenTelemetry feature not enabled, using standard logging");
96    crate::logging::init_logging(logging_config)?;
97    Ok(())
98}
99
100#[cfg(not(feature = "opentelemetry"))]
101pub fn shutdown_otel() {
102    // No-op when OpenTelemetry is not enabled
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_default_otel_config() {
111        let config = OtelTracingConfig::default();
112        assert_eq!(config.service_name, "mockforge");
113        assert_eq!(config.environment, "development");
114        assert_eq!(config.sampling_rate, 1.0);
115        assert_eq!(config.protocol, "grpc");
116    }
117
118    #[test]
119    fn test_custom_otel_config() {
120        let config = OtelTracingConfig {
121            service_name: "test-service".to_string(),
122            environment: "production".to_string(),
123            jaeger_endpoint: Some("http://jaeger:14268/api/traces".to_string()),
124            otlp_endpoint: Some("http://otel:4317".to_string()),
125            protocol: "http".to_string(),
126            sampling_rate: 0.5,
127        };
128
129        assert_eq!(config.service_name, "test-service");
130        assert_eq!(config.environment, "production");
131        assert_eq!(config.sampling_rate, 0.5);
132    }
133}