ant_quic/logging/
components.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/// Component-specific logging functions
9///
10/// Provides specialized logging for different components of the QUIC stack
11use std::collections::HashMap;
12use tracing::{debug, trace};
13
14use crate::{ConnectionId, Frame};
15
16use super::{ConnectionInfo, FrameInfo, LogEvent, NatTraversalInfo, TransportParamInfo, logger};
17
18/// Connection event types
19#[derive(Debug, Clone, Copy)]
20pub enum ConnectionEventType {
21    /// Connection initialization requested
22    Initiated,
23    /// TLS/QUIC handshake has begun
24    HandshakeStarted,
25    /// TLS/QUIC handshake completed successfully
26    HandshakeCompleted,
27    /// Connection established and ready for data
28    Established,
29    /// Path migration occurred (address change)
30    Migrated,
31    /// Connection closed gracefully
32    Closed,
33    /// Connection lost unexpectedly
34    Lost,
35    /// Progress stalled (no forward movement)
36    Stalled,
37}
38
39/// Frame event types
40#[derive(Debug, Clone, Copy)]
41pub enum FrameEventType {
42    /// A frame was sent
43    Sent,
44    /// A frame was received
45    Received,
46    /// A frame was dropped before delivery
47    Dropped,
48    /// A frame was retransmitted
49    Retransmitted,
50    /// A frame was acknowledged
51    Acknowledged,
52}
53
54/// Transport parameter event types
55#[derive(Debug, Clone, Copy)]
56pub enum TransportParamEventType {
57    /// Transport parameters were sent
58    Sent,
59    /// Transport parameters were received
60    Received,
61    /// Transport parameters were successfully negotiated
62    Negotiated,
63    /// Transport parameters were rejected
64    Rejected,
65    /// Transport parameters were invalid
66    Invalid,
67}
68
69/// NAT traversal event types
70#[derive(Debug, Clone, Copy)]
71pub enum NatTraversalEventType {
72    /// NAT traversal initiated
73    Started,
74    /// A candidate address was discovered
75    CandidateDiscovered,
76    /// A candidate address was validated
77    CandidateValidated,
78    /// Hole punching began
79    HolePunchingStarted,
80    /// Hole punching succeeded
81    HolePunchingSucceeded,
82    /// Hole punching failed
83    HolePunchingFailed,
84    /// NAT traversal completed
85    Completed,
86    /// NAT traversal failed
87    Failed,
88}
89
90/// Log a connection event
91pub fn log_connection_event(event_type: ConnectionEventType, conn_info: &ConnectionInfo) {
92    let message = match event_type {
93        ConnectionEventType::Initiated => "connection.initiated",
94        ConnectionEventType::HandshakeStarted => "connection.handshake_started",
95        ConnectionEventType::HandshakeCompleted => "connection.handshake_completed",
96        ConnectionEventType::Established => "connection.established",
97        ConnectionEventType::Migrated => "connection.migrated",
98        ConnectionEventType::Closed => "connection.closed",
99        ConnectionEventType::Lost => "connection.lost",
100        ConnectionEventType::Stalled => "connection.stalled",
101    };
102
103    let mut fields = HashMap::new();
104    fields.insert("conn_id".to_string(), format!("{:?}", conn_info.id));
105    fields.insert("remote_addr".to_string(), conn_info.remote_addr.to_string());
106    fields.insert("role".to_string(), format!("{:?}", conn_info.role));
107    fields.insert("event_type".to_string(), format!("{event_type:?}"));
108
109    let level = match event_type {
110        ConnectionEventType::Lost | ConnectionEventType::Stalled => tracing::Level::WARN,
111        ConnectionEventType::Closed => tracing::Level::DEBUG,
112        _ => tracing::Level::INFO,
113    };
114
115    logger().log_event(LogEvent {
116        timestamp: crate::Instant::now(),
117        level,
118        target: "ant_quic::connection".to_string(),
119        message: message.to_string(),
120        fields,
121        span_id: None,
122    });
123}
124
125/// Log a frame event
126pub fn log_frame_event(event_type: FrameEventType, frame_info: &FrameInfo) {
127    let message = match event_type {
128        FrameEventType::Sent => "frame.sent",
129        FrameEventType::Received => "frame.received",
130        FrameEventType::Dropped => "frame.dropped",
131        FrameEventType::Retransmitted => "frame.retransmitted",
132        FrameEventType::Acknowledged => "frame.acknowledged",
133    };
134
135    let mut fields = HashMap::new();
136    fields.insert(
137        "frame_type".to_string(),
138        format!("{:?}", frame_info.frame_type),
139    );
140    fields.insert("size".to_string(), frame_info.size.to_string());
141    if let Some(pn) = frame_info.packet_number {
142        fields.insert("packet_number".to_string(), pn.to_string());
143    }
144    fields.insert("event_type".to_string(), format!("{event_type:?}"));
145
146    let level = match event_type {
147        FrameEventType::Dropped => tracing::Level::WARN,
148        _ => tracing::Level::TRACE,
149    };
150
151    logger().log_event(LogEvent {
152        timestamp: crate::Instant::now(),
153        level,
154        target: "ant_quic::frame".to_string(),
155        message: message.to_string(),
156        fields,
157        span_id: None,
158    });
159}
160
161/// Log a transport parameter event
162pub fn log_transport_param_event(
163    event_type: TransportParamEventType,
164    param_info: &TransportParamInfo,
165) {
166    let message = match event_type {
167        TransportParamEventType::Sent => "transport_param.sent",
168        TransportParamEventType::Received => "transport_param.received",
169        TransportParamEventType::Negotiated => "transport_param.negotiated",
170        TransportParamEventType::Rejected => "transport_param.rejected",
171        TransportParamEventType::Invalid => "transport_param.invalid",
172    };
173
174    let mut fields = HashMap::new();
175    fields.insert("param_id".to_string(), format!("{:?}", param_info.param_id));
176    fields.insert("side".to_string(), format!("{:?}", param_info.side));
177    if let Some(value) = &param_info.value {
178        fields.insert("value_len".to_string(), value.len().to_string());
179    }
180    fields.insert("event_type".to_string(), format!("{event_type:?}"));
181
182    let level = match event_type {
183        TransportParamEventType::Rejected | TransportParamEventType::Invalid => {
184            tracing::Level::WARN
185        }
186        _ => tracing::Level::DEBUG,
187    };
188
189    logger().log_event(LogEvent {
190        timestamp: crate::Instant::now(),
191        level,
192        target: "ant_quic::transport_params".to_string(),
193        message: message.to_string(),
194        fields,
195        span_id: None,
196    });
197}
198
199/// Log a NAT traversal event
200pub fn log_nat_traversal_event(event_type: NatTraversalEventType, nat_info: &NatTraversalInfo) {
201    let message = match event_type {
202        NatTraversalEventType::Started => "nat_traversal.started",
203        NatTraversalEventType::CandidateDiscovered => "nat_traversal.candidate_discovered",
204        NatTraversalEventType::CandidateValidated => "nat_traversal.candidate_validated",
205        NatTraversalEventType::HolePunchingStarted => "nat_traversal.hole_punching_started",
206        NatTraversalEventType::HolePunchingSucceeded => "nat_traversal.hole_punching_succeeded",
207        NatTraversalEventType::HolePunchingFailed => "nat_traversal.hole_punching_failed",
208        NatTraversalEventType::Completed => "nat_traversal.completed",
209        NatTraversalEventType::Failed => "nat_traversal.failed",
210    };
211
212    let mut fields = HashMap::new();
213    fields.insert("role".to_string(), format!("{:?}", nat_info.role));
214    fields.insert("remote_addr".to_string(), nat_info.remote_addr.to_string());
215    fields.insert(
216        "candidate_count".to_string(),
217        nat_info.candidate_count.to_string(),
218    );
219    fields.insert("event_type".to_string(), format!("{event_type:?}"));
220
221    let level = match event_type {
222        NatTraversalEventType::HolePunchingFailed | NatTraversalEventType::Failed => {
223            tracing::Level::WARN
224        }
225        NatTraversalEventType::HolePunchingSucceeded | NatTraversalEventType::Completed => {
226            tracing::Level::INFO
227        }
228        _ => tracing::Level::DEBUG,
229    };
230
231    logger().log_event(LogEvent {
232        timestamp: crate::Instant::now(),
233        level,
234        target: "ant_quic::nat_traversal".to_string(),
235        message: message.to_string(),
236        fields,
237        span_id: None,
238    });
239}
240
241/// Log error with full context
242pub fn log_error_with_context(error: &dyn std::error::Error, context: super::ErrorContext) {
243    let mut fields = HashMap::new();
244    fields.insert("component".to_string(), context.component.to_string());
245    fields.insert("operation".to_string(), context.operation.to_string());
246
247    if let Some(conn_id) = context.connection_id {
248        fields.insert("conn_id".to_string(), format!("{conn_id:?}"));
249    }
250
251    // Add error chain
252    let mut error_chain = Vec::new();
253    let mut current_error: &dyn std::error::Error = error;
254    error_chain.push(current_error.to_string());
255
256    while let Some(source) = current_error.source() {
257        error_chain.push(source.to_string());
258        current_error = source;
259    }
260
261    fields.insert("error_chain".to_string(), error_chain.join(" -> "));
262
263    for (key, value) in context.additional_fields {
264        fields.insert(key.to_string(), value.to_string());
265    }
266
267    logger().log_event(LogEvent {
268        timestamp: crate::Instant::now(),
269        level: tracing::Level::ERROR,
270        target: format!("ant_quic::{}", context.component),
271        message: error.to_string(),
272        fields,
273        span_id: None,
274    });
275}
276
277/// Log detailed frame information
278#[allow(dead_code)]
279pub(crate) fn log_frame_details(frame: &Frame, direction: &str, conn_id: &ConnectionId) {
280    trace!(
281        target: "ant_quic::frame::details",
282        conn_id = ?conn_id,
283        direction = direction,
284        frame_type = ?frame.ty(),
285        "Processing frame"
286    );
287
288    match frame {
289        Frame::ObservedAddress(addr) => {
290            debug!(
291                target: "ant_quic::frame::observed_address",
292                conn_id = ?conn_id,
293                sequence_number = addr.sequence_number.0,
294                address = ?addr.address,
295                "OBSERVED_ADDRESS frame"
296            );
297        }
298        Frame::AddAddress(addr) => {
299            debug!(
300                target: "ant_quic::frame::add_address",
301                conn_id = ?conn_id,
302                sequence = addr.sequence.0,
303                address = ?addr.address,
304                priority = addr.priority.0,
305                "ADD_ADDRESS frame"
306            );
307        }
308        Frame::PunchMeNow(punch) => {
309            debug!(
310                target: "ant_quic::frame::punch_me_now",
311                conn_id = ?conn_id,
312                paired_with_sequence_number = punch.paired_with_sequence_number.0,
313                round = punch.round.0,
314                "PUNCH_ME_NOW frame"
315            );
316        }
317        _ => {
318            trace!(
319                target: "ant_quic::frame::other",
320                conn_id = ?conn_id,
321                frame_type = ?frame.ty(),
322                "Standard QUIC frame"
323            );
324        }
325    }
326}
327
328/// Log packet-level events
329pub fn log_packet_event(
330    event: &str,
331    conn_id: &ConnectionId,
332    packet_number: u64,
333    size: usize,
334    details: Vec<(&str, &str)>,
335) {
336    let mut fields = HashMap::new();
337    fields.insert("conn_id".to_string(), format!("{conn_id:?}"));
338    fields.insert("packet_number".to_string(), packet_number.to_string());
339    fields.insert("size".to_string(), size.to_string());
340
341    for (key, value) in details {
342        fields.insert(key.to_string(), value.to_string());
343    }
344
345    logger().log_event(LogEvent {
346        timestamp: crate::Instant::now(),
347        level: tracing::Level::TRACE,
348        target: "ant_quic::packet".to_string(),
349        message: event.to_string(),
350        fields,
351        span_id: None,
352    });
353}
354
355/// Log stream events
356pub fn log_stream_event(
357    event: &str,
358    conn_id: &ConnectionId,
359    stream_id: crate::StreamId,
360    details: Vec<(&str, &str)>,
361) {
362    let mut fields = HashMap::new();
363    fields.insert("conn_id".to_string(), format!("{conn_id:?}"));
364    fields.insert("stream_id".to_string(), format!("{stream_id}"));
365
366    for (key, value) in details {
367        fields.insert(key.to_string(), value.to_string());
368    }
369
370    logger().log_event(LogEvent {
371        timestamp: crate::Instant::now(),
372        level: tracing::Level::DEBUG,
373        target: "ant_quic::stream".to_string(),
374        message: event.to_string(),
375        fields,
376        span_id: None,
377    });
378}