ant_quic/logging/
mod.rs

1/// Comprehensive Logging System for ant-quic
2///
3/// This module provides structured logging capabilities for debugging,
4/// monitoring, and analyzing QUIC connections, NAT traversal, and
5/// protocol-level events.
6use std::collections::HashMap;
7use std::net::SocketAddr;
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::sync::{Arc, Mutex};
10
11use tracing::{Level, Span, debug, error, info, trace, warn};
12use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
13
14use crate::{
15    ConnectionId, Duration, Instant, Side, connection::nat_traversal::NatTraversalRole,
16    frame::FrameType, transport_parameters::TransportParameterId,
17};
18
19#[cfg(test)]
20mod tests;
21
22mod components;
23mod filters;
24mod formatters;
25mod lifecycle;
26pub mod metrics;
27mod structured;
28
29pub use components::*;
30pub use filters::*;
31pub use formatters::*;
32pub use lifecycle::*;
33pub use metrics::*;
34pub use structured::*;
35
36/// Global logger instance
37static LOGGER: once_cell::sync::OnceCell<Arc<Logger>> = once_cell::sync::OnceCell::new();
38
39/// Initialize the logging system
40pub fn init_logging(config: LoggingConfig) -> Result<(), LoggingError> {
41    let logger = Arc::new(Logger::new(config)?);
42
43    LOGGER
44        .set(logger.clone())
45        .map_err(|_| LoggingError::AlreadyInitialized)?;
46
47    // Initialize tracing subscriber
48    let env_filter = EnvFilter::from_default_env().add_directive("ant_quic=debug".parse().unwrap());
49
50    if logger.use_json() {
51        let fmt_layer = tracing_subscriber::fmt::layer()
52            .json()
53            .with_target(true)
54            .with_thread_ids(true)
55            .with_level(true);
56
57        tracing_subscriber::registry()
58            .with(env_filter)
59            .with(fmt_layer)
60            .init();
61    } else {
62        let fmt_layer = tracing_subscriber::fmt::layer()
63            .with_target(true)
64            .with_thread_ids(true)
65            .with_level(true);
66
67        tracing_subscriber::registry()
68            .with(env_filter)
69            .with(fmt_layer)
70            .init();
71    }
72
73    info!("ant-quic logging system initialized");
74    Ok(())
75}
76
77/// Get the global logger instance
78pub fn logger() -> Arc<Logger> {
79    LOGGER.get().cloned().unwrap_or_else(|| {
80        // Create default logger if not initialized
81        let config = LoggingConfig::default();
82        let logger = Arc::new(Logger::new(config).expect("Failed to create default logger"));
83        let _ = LOGGER.set(logger.clone());
84        logger
85    })
86}
87
88/// Main logger struct
89pub struct Logger {
90    config: LoggingConfig,
91    metrics_collector: Arc<MetricsCollector>,
92    event_buffer: Arc<Mutex<Vec<LogEvent>>>,
93    rate_limiter: Arc<RateLimiter>,
94}
95
96impl Logger {
97    /// Create a new logger with the given configuration
98    pub fn new(config: LoggingConfig) -> Result<Self, LoggingError> {
99        let rate_limit = config.rate_limit_per_second;
100        let buffer_size = config.event_buffer_size;
101        Ok(Self {
102            config,
103            metrics_collector: Arc::new(MetricsCollector::new()),
104            event_buffer: Arc::new(Mutex::new(Vec::with_capacity(buffer_size))),
105            rate_limiter: Arc::new(RateLimiter::new(rate_limit, Duration::from_secs(1))),
106        })
107    }
108
109    /// Check if JSON output is enabled
110    fn use_json(&self) -> bool {
111        self.config.json_output
112    }
113
114    /// Log a structured event
115    pub fn log_event(&self, event: LogEvent) {
116        if !self.rate_limiter.should_log(event.level) {
117            return;
118        }
119
120        // Add to buffer for analysis
121        if let Ok(mut buffer) = self.event_buffer.lock() {
122            if buffer.len() < 10000 {
123                buffer.push(event.clone());
124            }
125        }
126
127        // Log using tracing
128        match event.level {
129            Level::ERROR => error!("{} - {}", event.target, event.message),
130            Level::WARN => warn!("{} - {}", event.target, event.message),
131            Level::INFO => info!("{} - {}", event.target, event.message),
132            Level::DEBUG => debug!("{} - {}", event.target, event.message),
133            Level::TRACE => trace!("{} - {}", event.target, event.message),
134        }
135
136        // Update metrics
137        self.metrics_collector.record_event(&event);
138    }
139
140    /// Get recent events for analysis
141    pub fn recent_events(&self, count: usize) -> Vec<LogEvent> {
142        match self.event_buffer.lock() {
143            Ok(buffer) => buffer.iter().rev().take(count).cloned().collect(),
144            _ => Vec::new(),
145        }
146    }
147
148    /// Get metrics summary
149    pub fn metrics_summary(&self) -> MetricsSummary {
150        self.metrics_collector.summary()
151    }
152}
153
154/// Logging configuration
155#[derive(Debug, Clone)]
156pub struct LoggingConfig {
157    /// Enable JSON output format
158    pub json_output: bool,
159    /// Rate limit per second
160    pub rate_limit_per_second: u64,
161    /// Component-specific log levels
162    pub component_levels: HashMap<String, Level>,
163    /// Enable performance metrics collection
164    pub collect_metrics: bool,
165    /// Buffer size for event storage
166    pub event_buffer_size: usize,
167}
168
169impl Default for LoggingConfig {
170    fn default() -> Self {
171        Self {
172            json_output: false,
173            rate_limit_per_second: 1000,
174            component_levels: HashMap::new(),
175            collect_metrics: true,
176            event_buffer_size: 10000,
177        }
178    }
179}
180
181/// Structured log event
182#[derive(Debug, Clone)]
183pub struct LogEvent {
184    pub timestamp: Instant,
185    pub level: Level,
186    pub target: String,
187    pub message: String,
188    pub fields: HashMap<String, String>,
189    pub span_id: Option<String>,
190}
191
192/// Connection role for logging
193#[derive(Debug, Clone, Copy)]
194pub enum ConnectionRole {
195    Client,
196    Server,
197}
198
199/// Connection information for logging
200#[derive(Debug, Clone)]
201pub struct ConnectionInfo {
202    pub id: ConnectionId,
203    pub remote_addr: SocketAddr,
204    pub role: ConnectionRole,
205}
206
207/// Frame information for logging
208#[derive(Debug)]
209pub struct FrameInfo {
210    pub frame_type: FrameType,
211    pub size: usize,
212    pub packet_number: Option<u64>,
213}
214
215/// Transport parameter information
216#[derive(Debug)]
217pub struct TransportParamInfo {
218    pub(crate) param_id: TransportParameterId,
219    pub value: Option<Vec<u8>>,
220    pub side: Side,
221}
222
223/// NAT traversal information
224#[derive(Debug)]
225pub struct NatTraversalInfo {
226    pub role: NatTraversalRole,
227    pub remote_addr: SocketAddr,
228    pub candidate_count: usize,
229}
230
231/// Error context for detailed logging
232#[derive(Debug, Default)]
233pub struct ErrorContext {
234    pub component: &'static str,
235    pub operation: &'static str,
236    pub connection_id: Option<ConnectionId>,
237    pub additional_fields: Vec<(&'static str, &'static str)>,
238}
239
240/// Warning context
241#[derive(Debug, Default)]
242pub struct WarningContext {
243    pub component: &'static str,
244    pub details: Vec<(&'static str, &'static str)>,
245}
246
247/// Info context
248#[derive(Debug, Default)]
249pub struct InfoContext {
250    pub component: &'static str,
251    pub details: Vec<(&'static str, &'static str)>,
252}
253
254/// Debug context
255#[derive(Debug, Default)]
256pub struct DebugContext {
257    pub component: &'static str,
258    pub details: Vec<(&'static str, &'static str)>,
259}
260
261/// Trace context
262#[derive(Debug, Default)]
263pub struct TraceContext {
264    pub component: &'static str,
265    pub details: Vec<(&'static str, &'static str)>,
266}
267
268/// Logging errors
269#[derive(Debug, thiserror::Error)]
270pub enum LoggingError {
271    #[error("Logging system already initialized")]
272    AlreadyInitialized,
273    #[error("Failed to initialize tracing subscriber: {0}")]
274    SubscriberError(String),
275}
276
277/// Rate limiter for preventing log spam
278pub struct RateLimiter {
279    max_events: u64,
280    window: Duration,
281    events_in_window: AtomicU64,
282    window_start: Mutex<Instant>,
283}
284
285impl RateLimiter {
286    pub fn new(max_events: u64, window: Duration) -> Self {
287        Self {
288            max_events,
289            window,
290            events_in_window: AtomicU64::new(0),
291            window_start: Mutex::new(Instant::now()),
292        }
293    }
294
295    pub fn should_log(&self, level: Level) -> bool {
296        // Always allow ERROR level
297        if level == Level::ERROR {
298            return true;
299        }
300
301        let now = Instant::now();
302        let mut window_start = self.window_start.lock().unwrap();
303
304        // Reset window if expired
305        if now.duration_since(*window_start) > self.window {
306            *window_start = now;
307            self.events_in_window.store(0, Ordering::Relaxed);
308        }
309
310        // Check rate limit
311        let current = self.events_in_window.fetch_add(1, Ordering::Relaxed);
312        current < self.max_events
313    }
314}
315
316// Convenience logging functions
317
318/// Log an error with context
319pub fn log_error(message: &str, context: ErrorContext) {
320    let mut fields = HashMap::new();
321    fields.insert("component".to_string(), context.component.to_string());
322    fields.insert("operation".to_string(), context.operation.to_string());
323
324    if let Some(conn_id) = context.connection_id {
325        fields.insert("conn_id".to_string(), format!("{conn_id:?}"));
326    }
327
328    for (key, value) in context.additional_fields {
329        fields.insert(key.to_string(), value.to_string());
330    }
331
332    logger().log_event(LogEvent {
333        timestamp: Instant::now(),
334        level: Level::ERROR,
335        target: format!("ant_quic::{}", context.component),
336        message: message.to_string(),
337        fields,
338        span_id: None,
339    });
340}
341
342/// Log a warning
343pub fn log_warning(message: &str, context: WarningContext) {
344    let mut fields = HashMap::new();
345    fields.insert("component".to_string(), context.component.to_string());
346
347    for (key, value) in context.details {
348        fields.insert(key.to_string(), value.to_string());
349    }
350
351    logger().log_event(LogEvent {
352        timestamp: Instant::now(),
353        level: Level::WARN,
354        target: format!("ant_quic::{}", context.component),
355        message: message.to_string(),
356        fields,
357        span_id: None,
358    });
359}
360
361/// Log info message
362pub fn log_info(message: &str, context: InfoContext) {
363    let mut fields = HashMap::new();
364    fields.insert("component".to_string(), context.component.to_string());
365
366    for (key, value) in context.details {
367        fields.insert(key.to_string(), value.to_string());
368    }
369
370    logger().log_event(LogEvent {
371        timestamp: Instant::now(),
372        level: Level::INFO,
373        target: format!("ant_quic::{}", context.component),
374        message: message.to_string(),
375        fields,
376        span_id: None,
377    });
378}
379
380/// Log debug message
381pub fn log_debug(message: &str, context: DebugContext) {
382    let mut fields = HashMap::new();
383    fields.insert("component".to_string(), context.component.to_string());
384
385    for (key, value) in context.details {
386        fields.insert(key.to_string(), value.to_string());
387    }
388
389    logger().log_event(LogEvent {
390        timestamp: Instant::now(),
391        level: Level::DEBUG,
392        target: format!("ant_quic::{}", context.component),
393        message: message.to_string(),
394        fields,
395        span_id: None,
396    });
397}
398
399/// Log trace message
400pub fn log_trace(message: &str, context: TraceContext) {
401    let mut fields = HashMap::new();
402    fields.insert("component".to_string(), context.component.to_string());
403
404    for (key, value) in context.details {
405        fields.insert(key.to_string(), value.to_string());
406    }
407
408    logger().log_event(LogEvent {
409        timestamp: Instant::now(),
410        level: Level::TRACE,
411        target: format!("ant_quic::{}", context.component),
412        message: message.to_string(),
413        fields,
414        span_id: None,
415    });
416}
417
418/// Create a span for connection operations
419pub fn create_connection_span(conn_id: &ConnectionId) -> Span {
420    tracing::span!(
421        Level::DEBUG,
422        "connection",
423        conn_id = %format!("{:?}", conn_id),
424    )
425}
426
427/// Create a span for frame processing
428pub fn create_frame_span(frame_type: FrameType) -> Span {
429    tracing::span!(
430        Level::TRACE,
431        "frame",
432        frame_type = ?frame_type,
433    )
434}