ant_quic/tracing/
mod.rs

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