ant_quic/tracing/
mod.rs

1//! Zero-cost tracing system for P2P network debugging
2//!
3//! This module provides comprehensive tracing capabilities with absolutely zero
4//! overhead in release builds when the `trace` feature is disabled.
5
6// Import modules at crate level
7mod context;
8mod event;
9mod macros;
10mod query;
11mod ring_buffer;
12
13#[cfg(feature = "trace-app")]
14mod app_protocol;
15
16#[cfg(feature = "trace")]
17mod implementation {
18    use std::sync::Arc;
19
20    // Re-export types from parent modules
21    pub use super::context::TraceContext;
22    pub use super::event::{Event, EventData, TraceId, socket_addr_to_bytes};
23    pub use super::query::{ConnectionAnalysis, TraceQuery};
24    pub use super::ring_buffer::{EventLog, TraceConfig};
25
26    #[cfg(feature = "trace-app")]
27    pub use super::app_protocol::{
28        AppProtocol, AppRegistry as AppProtocolRegistry, DataMapProtocol,
29    };
30
31    /// Global event log instance
32    static EVENT_LOG: once_cell::sync::Lazy<Arc<EventLog>> =
33        once_cell::sync::Lazy::new(|| Arc::new(EventLog::new()));
34
35    /// Get the global event log
36    pub fn global_log() -> Arc<EventLog> {
37        EVENT_LOG.clone()
38    }
39
40    #[cfg(feature = "trace-app")]
41    static APP_REGISTRY: once_cell::sync::Lazy<AppProtocolRegistry> =
42        once_cell::sync::Lazy::new(AppProtocolRegistry::new);
43
44    #[cfg(feature = "trace-app")]
45    pub fn global_app_registry() -> &'static AppProtocolRegistry {
46        &APP_REGISTRY
47    }
48}
49
50// When trace is disabled, export empty types and no-op functions
51#[cfg(not(feature = "trace"))]
52mod implementation {
53    use std::sync::Arc;
54
55    /// Zero-sized trace ID when tracing is disabled
56    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57    pub struct TraceId;
58
59    impl Default for TraceId {
60        fn default() -> Self {
61            Self::new()
62        }
63    }
64
65    impl TraceId {
66        pub fn new() -> Self {
67            Self
68        }
69    }
70
71    /// Zero-sized event when tracing is disabled
72    #[derive(Debug)]
73    pub struct Event;
74
75    /// Zero-sized event log when tracing is disabled
76    #[derive(Debug)]
77    pub struct EventLog;
78
79    impl Default for EventLog {
80        fn default() -> Self {
81            Self::new()
82        }
83    }
84
85    impl EventLog {
86        pub fn new() -> Self {
87            Self
88        }
89        pub fn log(&self, _event: Event) {}
90        pub fn recent_events(&self, _count: usize) -> Vec<Event> {
91            Vec::new()
92        }
93        pub fn get_events_by_trace(&self, _trace_id: TraceId) -> Vec<Event> {
94            Vec::new()
95        }
96    }
97
98    /// Zero-sized trace context when tracing is disabled
99    #[derive(Debug, Clone)]
100    pub struct TraceContext;
101
102    impl TraceContext {
103        pub fn new(_trace_id: TraceId) -> Self {
104            Self
105        }
106        pub fn trace_id(&self) -> TraceId {
107            TraceId
108        }
109    }
110
111    /// Zero-sized trace flags when tracing is disabled
112    #[derive(Debug, Clone, Copy)]
113    pub struct TraceFlags;
114
115    impl Default for TraceFlags {
116        fn default() -> Self {
117            Self
118        }
119    }
120
121    /// No-op global log when tracing is disabled
122    pub fn global_log() -> Arc<EventLog> {
123        Arc::new(EventLog)
124    }
125}
126
127// Re-export everything from implementation
128pub use implementation::*;
129
130// Helper function to get current timestamp in microseconds
131#[cfg(feature = "trace")]
132pub fn timestamp_now() -> u64 {
133    use std::time::{SystemTime, UNIX_EPOCH};
134    SystemTime::now()
135        .duration_since(UNIX_EPOCH)
136        .unwrap()
137        .as_micros() as u64
138}
139
140#[cfg(not(feature = "trace"))]
141pub fn timestamp_now() -> u64 {
142    0
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn test_zero_sized_types() {
151        // When trace is disabled, all types should be zero-sized
152        #[cfg(not(feature = "trace"))]
153        {
154            assert_eq!(std::mem::size_of::<TraceId>(), 0);
155            assert_eq!(std::mem::size_of::<Event>(), 0);
156            assert_eq!(std::mem::size_of::<EventLog>(), 0);
157            assert_eq!(std::mem::size_of::<TraceContext>(), 0);
158            assert_eq!(std::mem::size_of::<TraceFlags>(), 0);
159        }
160    }
161
162    #[test]
163    fn test_no_op_operations() {
164        let log = EventLog::new();
165        #[cfg(not(feature = "trace"))]
166        log.log(Event); // Should compile to nothing when trace is disabled
167        #[cfg(feature = "trace")]
168        {
169            // When trace is enabled, Event is a real struct
170            let event = Event::default();
171            log.log(event);
172        }
173
174        let trace_id = TraceId::new();
175        let _context = TraceContext::new(trace_id);
176    }
177}