qevent/
lib.rs

1pub mod legacy;
2pub mod loglevel;
3pub mod quic;
4pub mod telemetry;
5
6#[doc(hidden)]
7pub mod macro_support;
8mod macros;
9pub mod packet;
10
11use std::{collections::HashMap, fmt::Display, net::SocketAddr};
12
13use bytes::Bytes;
14use derive_builder::Builder;
15use derive_more::{Display, From, Into};
16use qbase::{cid::ConnectionId, role::Role, util::ContinuousData};
17use quic::ConnectionID;
18use serde::{Deserialize, Serialize};
19
20#[serde_with::skip_serializing_none]
21#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
22#[builder(setter(into, strip_option), build_fn(private, name = "fallible_build"))]
23pub struct LogFile {
24    file_schema: String,
25    serialization_format: String,
26    #[builder(default)]
27    title: Option<String>,
28    #[builder(default)]
29    description: Option<String>,
30    #[builder(default)]
31    event_schemas: Vec<String>,
32}
33
34#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq)]
35#[builder(setter(into), build_fn(private, name = "fallible_build"))]
36pub struct QlogFile {
37    #[serde(flatten)]
38    log_file: LogFile,
39    traces: Vec<Traces>,
40}
41
42/// A qlog file using the QlogFileSeq schema can be serialized to a
43/// streamable JSON format called JSON Text Sequences (JSON-SEQ)
44/// ([RFC7464]). The top-level element in this schema defines only a
45/// small set of "header" fields and an array of component traces.
46///
47/// [RFC7464]: https://www.rfc-editor.org/rfc/rfc7464
48#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq)]
49#[builder(setter(into), build_fn(private, name = "fallible_build"))]
50pub struct QlogFileSeq {
51    #[serde(flatten)]
52    log_file: LogFile,
53    trace_seq: TraceSeq,
54}
55
56impl QlogFileSeq {
57    pub const SCHEMA: &'static str = "urn:ietf:params:qlog:file:sequential";
58}
59
60#[allow(clippy::large_enum_variant)]
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
62#[serde(untagged)]
63pub enum Traces {
64    Trace(Trace),
65    TraceError(TraceError),
66}
67
68///  The exact conceptual definition of a Trace can be fluid.  For
69/// example, a trace could contain all events for a single connection,
70/// for a single endpoint, for a single measurement interval, for a
71/// single protocol, etc.  In the normal use case however, a trace is a
72/// log of a single data flow collected at a single location or vantage
73/// point.  For example, for QUIC, a single trace only contains events
74/// for a single logical QUIC connection for either the client or the
75/// server.
76#[serde_with::skip_serializing_none]
77#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq)]
78#[builder(setter(into, strip_option), build_fn(private, name = "fallible_build"))]
79pub struct Trace {
80    /// The optional "title" fields provide additional free-text information about the trace.
81    #[builder(default)]
82    title: Option<String>,
83    /// The optional "description" fields provide additional free-text information about the trace.
84    #[builder(default)]
85    description: Option<String>,
86    #[builder(default)]
87    common_fields: Option<CommonFields>,
88    #[builder(default)]
89    vantage_point: Option<VantagePoint>,
90    events: Vec<Event>,
91}
92
93/// TraceSeq is used with QlogFileSeq. It is conceptually similar to a
94/// Trace, with the exception that qlog events are not contained within
95/// it, but rather appended after it in a QlogFileSeq.
96#[serde_with::skip_serializing_none]
97#[derive(Builder, Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
98#[builder(
99    default,
100    setter(into, strip_option),
101    build_fn(private, name = "fallible_build")
102)]
103pub struct TraceSeq {
104    /// The optional "title" fields provide additional free-text information about the trace.
105    title: Option<String>,
106    /// The optional "description" fields provide additional free-text information about the trace.
107    description: Option<String>,
108    common_fields: Option<CommonFields>,
109    vantage_point: Option<VantagePoint>,
110}
111
112#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
113#[builder(setter(into, strip_option), build_fn(private, name = "fallible_build"))]
114pub struct CommonFields {
115    path: PathID,
116    time_format: TimeFormat,
117    reference_time: ReferenceTime,
118    protocol_types: ProtocolTypeList,
119    group_id: GroupID,
120    #[builder(default)]
121    #[serde(flatten)]
122    #[serde(skip_serializing_if = "HashMap::is_empty")]
123    //  * text => any
124    custom_fields: HashMap<String, serde_json::Value>,
125}
126
127/// A VantagePoint describes the vantage point from which a trace originates
128#[serde_with::skip_serializing_none]
129#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
130#[builder(setter(into, strip_option), build_fn(private, name = "fallible_build"))]
131pub struct VantagePoint {
132    #[builder(default)]
133    name: Option<String>,
134    r#type: VantagePointType,
135    #[builder(default)]
136    flow: Option<VantagePointType>,
137}
138
139#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
140#[serde(rename_all = "snake_case")]
141pub enum VantagePointType {
142    /// endpoint which initiates the connection
143    Client,
144    /// endpoint which accepts the connection
145    Server,
146    /// observer in between client and server
147    Network,
148    #[default]
149    Unknow,
150}
151
152impl From<Role> for VantagePointType {
153    fn from(role: Role) -> Self {
154        match role {
155            Role::Client => VantagePointType::Client,
156            Role::Server => VantagePointType::Server,
157        }
158    }
159}
160
161impl Display for VantagePointType {
162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163        match self {
164            VantagePointType::Client => write!(f, "client"),
165            VantagePointType::Server => write!(f, "server"),
166            VantagePointType::Network => write!(f, "network"),
167            VantagePointType::Unknow => write!(f, "unknow"),
168        }
169    }
170}
171
172#[serde_with::skip_serializing_none]
173#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq)]
174#[builder(setter(into, strip_option), build_fn(private, name = "fallible_build"))]
175pub struct TraceError {
176    error_description: String,
177    #[builder(default)]
178    uri: Option<String>,
179    #[builder(default)]
180    vantage_point: Option<VantagePoint>,
181}
182
183/// Events are logged at a time instant and convey specific details of the logging use case.
184///
185/// Events can contain any amount of custom fields.
186#[serde_with::skip_serializing_none]
187#[derive(Builder, Debug, Clone, Serialize, Deserialize, PartialEq)]
188#[builder(setter(into, strip_option), build_fn(private, name = "fallible_build"))]
189pub struct Event {
190    time: f64,
191    #[serde(flatten)]
192    data: EvnetData,
193    /// A qlog event can be associated with a single "network path" (usually, but not always, identified by a 4-tuple
194    /// of IP addresses and ports). In many cases, the path will be the same for all events in a given trace, and does
195    /// not need to be logged explicitly with each event. In this case, the "path" field can be omitted (in which case
196    /// the default value of "" is assumed) or reflected in "common_fields" instead
197    #[builder(default)]
198    path: Option<PathID>,
199    #[builder(default)]
200    time_format: Option<TimeFormat>,
201    #[builder(default)]
202    protocol_types: Option<ProtocolTypeList>,
203    #[builder(default)]
204    group_id: Option<GroupID>,
205    #[builder(default)]
206    system_info: Option<SystemInformation>,
207    /// events can contain any amount of custom fields
208    #[builder(default)]
209    #[serde(flatten)]
210    #[serde(skip_serializing_if = "HashMap::is_empty")]
211    // * text => any
212    custom_fields: HashMap<String, serde_json::Value>,
213}
214
215#[derive(Debug, Clone, From, Into, Serialize, Deserialize, PartialEq, Eq)]
216#[serde(transparent)]
217pub struct PathID(String);
218
219#[serde_with::skip_serializing_none]
220#[derive(Builder, Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
221#[builder(
222    default,
223    setter(into, strip_option),
224    build_fn(private, name = "fallible_build")
225)]
226#[serde(try_from = "UncheckedReferenceTime")]
227pub struct ReferenceTime {
228    /// The required "clock_type" field represents the type of clock used for time measurements. The value "system"
229    /// represents a clock that uses system time, commonly measured against a chosen or well-known epoch. However,
230    /// depending on the system, System time can potentially jump forward or back. In contrast, a clock using monotonic
231    /// time is generally guaranteed to never go backwards. The value "monotonic" represents such a clock.
232    clock_type: TimeClockType,
233    /// The required "epoch" field is the start of the ReferenceTime. When using the "system" clock type, the epoch field
234    /// **SHOULD** have a date/time value using the format defined in [RFC3339]. However, the value "unknown" **MAY** be
235    /// used
236    ///
237    /// [RFC3339]: https://www.rfc-editor.org/rfc/rfc3339
238    #[serde(default)]
239    epoch: TimeEpoch,
240    /// The optional "wall_clock_time" field can be used to provide an approximate date/time value that logging commenced
241    /// at if the epoch value is "unknown". It uses the format defined in [RFC3339]. Note that conversion of timestamps
242    /// to calendar time based on wall clock times cannot be safely relied on.
243    ///
244    /// [RFC3339]: https://www.rfc-editor.org/rfc/rfc3339
245    #[builder(default)]
246    wall_clock_time: Option<RFC3339DateTime>,
247}
248
249/// Intermediate data types during deserialization
250#[derive(Deserialize)]
251struct UncheckedReferenceTime {
252    clock_type: TimeClockType,
253    #[serde(default)]
254    epoch: TimeEpoch,
255    wall_clock_time: Option<RFC3339DateTime>,
256}
257
258impl TryFrom<UncheckedReferenceTime> for ReferenceTime {
259    type Error = &'static str;
260    fn try_from(value: UncheckedReferenceTime) -> Result<Self, Self::Error> {
261        if value.clock_type == TimeClockType::Monotaonic && value.epoch != TimeEpoch::Unknow {
262            return Err(
263                r#"When using the "monotonic" clock type, the epoch field MUST have the value "unknown"."#,
264            );
265        }
266
267        Ok(ReferenceTime {
268            clock_type: value.clock_type,
269            epoch: value.epoch,
270            wall_clock_time: value.wall_clock_time,
271        })
272    }
273}
274
275#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
276#[serde(rename_all = "snake_case")]
277pub enum TimeClockType {
278    /// The value "system" represents a clock that uses system time, commonly measured against a chosen or well-known
279    /// epoch
280    #[default]
281    System,
282    /// A clock using monotonic time is generally guaranteed to never go backwards. The value "monotonic" represents
283    /// such a clock.
284    ///
285    /// When using the "monotonic" clock type, the epoch field MUST have the value "unknown".
286    Monotaonic,
287    #[serde(untagged)]
288    Custom(String),
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
292pub enum TimeEpoch {
293    Unknow,
294    #[serde(untagged)]
295    RFC3339DateTime(RFC3339DateTime),
296}
297
298impl Default for TimeEpoch {
299    fn default() -> Self {
300        Self::RFC3339DateTime(Default::default())
301    }
302}
303
304#[derive(Debug, Clone, From, Into, Serialize, Deserialize, PartialEq, Eq)]
305#[serde(transparent)]
306pub struct RFC3339DateTime(String);
307
308impl Default for RFC3339DateTime {
309    fn default() -> Self {
310        Self("1970-01-01T00:00:00.000Z".to_owned())
311    }
312}
313
314#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
315#[serde(rename_all = "snake_case")]
316pub enum TimeFormat {
317    /// A duration relative to the ReferenceTime "epoch" field. This approach uses the largest amount of characters.
318    /// It is good for stateless loggers. This is the default value of the "time_format" field.
319    #[default]
320    RelativeToEpoch,
321    /// A delta-encoded value, based on the previously logged value. The first event in a trace is always relative to
322    /// the ReferenceTime. This approach uses the least amount of characters. It is suitable for stateful loggers.
323    RelativeToPreviousEvent,
324}
325
326#[derive(Debug, Clone, From, Into, Serialize, Deserialize, PartialEq, Eq)]
327#[serde(transparent)]
328pub struct ProtocolTypeList(Vec<ProtocolType>);
329
330#[derive(Debug, Clone, From, Into, Serialize, Deserialize, PartialEq, Eq)]
331#[serde(transparent)]
332pub struct ProtocolType(String);
333
334impl ProtocolType {
335    pub fn quic() -> ProtocolType {
336        ProtocolType("QUIC".to_owned())
337    }
338
339    pub fn http3() -> ProtocolType {
340        ProtocolType("HTTP/3".to_owned())
341    }
342}
343
344#[derive(Debug, Display, Clone, From, Into, Serialize, Deserialize, PartialEq, Eq)]
345#[serde(transparent)]
346pub struct GroupID(String);
347
348impl From<ConnectionId> for GroupID {
349    fn from(value: ConnectionId) -> Self {
350        Self(format!("{value:x}"))
351    }
352}
353
354impl From<ConnectionID> for GroupID {
355    fn from(value: ConnectionID) -> Self {
356        Self(format!("{value:x}"))
357    }
358}
359
360impl From<(SocketAddr, SocketAddr)> for GroupID {
361    fn from(_value: (SocketAddr, SocketAddr)) -> Self {
362        todo!()
363    }
364}
365
366/// The "system_info" field can be used to record system-specific details related to an event. This is useful, for instance,
367/// where an application splits work across CPUs, processes, or threads and events for a single trace occur on potentially
368/// different combinations thereof. Each field is optional to support deployment diversity.
369#[derive(Builder, Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
370#[serde_with::skip_serializing_none]
371#[builder(
372    default,
373    setter(into, strip_option),
374    build_fn(private, name = "fallible_build")
375)]
376pub struct SystemInformation {
377    processor_id: Option<u32>,
378    process_id: Option<u32>,
379    thread_id: Option<u32>,
380}
381
382#[derive(Debug, Clone, Copy, PartialEq, Eq)]
383pub enum EventImportance {
384    Core = 1,
385    Base = 2,
386    Extra = 3,
387}
388
389#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
390#[serde(tag = "name", content = "data")]
391#[enum_dispatch::enum_dispatch(BeEventData)]
392pub enum EvnetData {
393    #[serde(rename = "quic:server_listening")]
394    ServerListening(quic::connectivity::ServerListening),
395    #[serde(rename = "quic:connection_started")]
396    ConnectionStarted(quic::connectivity::ConnectionStarted),
397    #[serde(rename = "quic:connection_closed")]
398    ConnectionClosed(quic::connectivity::ConnectionClosed),
399    #[serde(rename = "quic:connection_id_updated")]
400    ConnectionIdUpdated(quic::connectivity::ConnectionIdUpdated),
401    #[serde(rename = "quic:spin_bit_updated")]
402    SpinBitUpdated(quic::connectivity::SpinBitUpdated),
403    #[serde(rename = "quic:connection_state_updated")]
404    ConnectionStateUpdated(quic::connectivity::ConnectionStateUpdated),
405    #[serde(rename = "quic:path_assigned")]
406    PathAssigned(quic::connectivity::PathAssigned),
407    #[serde(rename = "quic:mtu_updated")]
408    MtuUpdated(quic::connectivity::MtuUpdated),
409    #[serde(rename = "quic:version_information")]
410    VersionInformation(quic::transport::VersionInformation),
411    #[serde(rename = "quic:alpn_information")]
412    ALPNInformation(quic::transport::ALPNInformation),
413    #[serde(rename = "quic:parameters_set")]
414    ParametersSet(quic::transport::ParametersSet),
415    #[serde(rename = "quic:parameters_restored")]
416    ParametersRestored(quic::transport::ParametersRestored),
417    #[serde(rename = "quic:packet_sent")]
418    PacketSent(quic::transport::PacketSent),
419    #[serde(rename = "quic:packet_received")]
420    PacketReceived(quic::transport::PacketReceived),
421    #[serde(rename = "quic:packet_dropped")]
422    PacketDropped(quic::transport::PacketDropped),
423    #[serde(rename = "quic:packet_buffered")]
424    PacketBuffered(quic::transport::PacketBuffered),
425    #[serde(rename = "quic:packets_acked")]
426    PacketsAcked(quic::transport::PacketsAcked),
427    #[serde(rename = "quic:udp_datagrams_sent")]
428    UdpDatagramSent(quic::transport::UdpDatagramsSent),
429    #[serde(rename = "quic:udp_datagrams_received")]
430    UdpDatagramReceived(quic::transport::UdpDatagramsReceived),
431    #[serde(rename = "quic:udp_datagram_dropped")]
432    UdpDatagramDropped(quic::transport::UdpDatagramDropped),
433    #[serde(rename = "quic:stream_state_updated")]
434    StreamStateUpdated(quic::transport::StreamStateUpdated),
435    #[serde(rename = "quic:frames_processed")]
436    FramesProcessed(quic::transport::FramesProcessed),
437    #[serde(rename = "quic:stream_data_moved")]
438    StreamDataMoved(quic::transport::StreamDataMoved),
439    #[serde(rename = "quic:datagram_data_moved")]
440    DatagramDataMoved(quic::transport::DatagramDataMoved),
441    #[serde(rename = "quic:migration_state_updated")]
442    MigrationStateUpdated(quic::transport::MigrationStateUpdated),
443    #[serde(rename = "quic:key_updated")]
444    KeyUpdated(quic::security::KeyUpdated),
445    #[serde(rename = "quic:key_discarded")]
446    KeyDiscarded(quic::security::KeyDiscarded),
447    #[serde(rename = "quic:recovery_parameters_set")]
448    RecoveryParametersSet(quic::recovery::RecoveryParametersSet),
449    #[serde(rename = "quic:recovery_metrics_updated")]
450    RecoveryMetricsUpdated(quic::recovery::RecoveryMetricsUpdated),
451    #[serde(rename = "quic:congestion_state_updated")]
452    CongestionStateUpdated(quic::recovery::CongestionStateUpdated),
453    #[serde(rename = "quic:loss_timer_updated")]
454    LossTimerUpdated(quic::recovery::LossTimerUpdated),
455    #[serde(rename = "quic:packet_lost")]
456    PacketLost(quic::recovery::PacketLost),
457    #[serde(rename = "quic:marked_for_retransmit")]
458    MarkedForRetransmit(quic::recovery::MarkedForRetransmit),
459    #[serde(rename = "quic:ecn_state_updated")]
460    ECNStateUpdated(quic::recovery::ECNStateUpdated),
461    #[serde(rename = "loglevel:error")]
462    Error(loglevel::Error),
463    #[serde(rename = "loglevel:warning")]
464    Warning(loglevel::Warning),
465    #[serde(rename = "loglevel:info")]
466    Info(loglevel::Info),
467    #[serde(rename = "loglevel:debug")]
468    Debug(loglevel::Debug),
469    #[serde(rename = "loglevel:verbose")]
470    Verbose(loglevel::Verbose),
471}
472
473pub trait BeSpecificEventData {
474    fn scheme() -> &'static str;
475
476    fn importance() -> EventImportance;
477}
478
479#[enum_dispatch::enum_dispatch]
480pub trait BeEventData {
481    fn scheme(&self) -> &'static str;
482
483    fn importance(&self) -> EventImportance;
484}
485
486impl<S: BeSpecificEventData> BeEventData for S {
487    #[inline]
488    fn scheme(&self) -> &'static str {
489        S::scheme()
490    }
491
492    #[inline]
493    fn importance(&self) -> EventImportance {
494        S::importance()
495    }
496}
497
498macro_rules! imp_be_events {
499    ( $($importance:ident $event:ty => $prefix:ident $schme:literal ;)* ) => {
500        $( imp_be_events!{@impl_one $importance $event => $prefix $schme ; } )*
501    };
502    (@impl_one $importance:ident $event:ty => urn $schme:literal ; ) => {
503        impl BeSpecificEventData for $event {
504            fn scheme() -> &'static str {
505                concat!["urn:ietf:params:qlog:events:",$schme]
506            }
507
508            fn importance() -> EventImportance {
509                EventImportance::$importance
510            }
511        }
512    };
513}
514
515imp_be_events! {
516    Extra quic::connectivity::ServerListening        => urn "quic:server_listening";
517    Base  quic::connectivity::ConnectionStarted      => urn "quic:connection_started";
518    Base  quic::connectivity::ConnectionClosed       => urn "quic:connection_closed";
519    Base  quic::connectivity::ConnectionIdUpdated    => urn "quic:connection_id_updated";
520    Base  quic::connectivity::SpinBitUpdated         => urn "quic:spin_bit_updated";
521    Base  quic::connectivity::ConnectionStateUpdated => urn "quic:connection_state_updated";
522    Base  quic::connectivity::PathAssigned           => urn "quic:path_assigned";
523    Extra quic::connectivity::MtuUpdated             => urn "quic:mtu_updated";
524    Core  quic::transport::VersionInformation        => urn "quic:version_information";
525    Core  quic::transport::ALPNInformation           => urn "quic:alpn_information";
526    Core  quic::transport::ParametersSet             => urn "quic:parameters_set";
527    Base  quic::transport::ParametersRestored        => urn "quic:parameters_restored";
528    Core  quic::transport::PacketSent                => urn "quic:packet_sent";
529    Core  quic::transport::PacketReceived            => urn "quic:packet_received";
530    Base  quic::transport::PacketDropped             => urn "quic:packet_dropped";
531    Base  quic::transport::PacketBuffered            => urn "quic:packet_buffered";
532    Extra quic::transport::PacketsAcked              => urn "quic:packets_acked";
533    Extra quic::transport::UdpDatagramsSent           => urn "quic:udp_datagrams_sent";
534    Extra quic::transport::UdpDatagramsReceived       => urn "quic:udp_datagrams_received";
535    Extra quic::transport::UdpDatagramDropped        => urn "quic:udp_datagram_dropped";
536    Base  quic::transport::StreamStateUpdated        => urn "quic:stream_state_updated";
537    Extra quic::transport::FramesProcessed           => urn "quic:frames_processed";
538    Base  quic::transport::StreamDataMoved           => urn "quic:stream_data_moved";
539    Base  quic::transport::DatagramDataMoved         => urn "quic:datagram_data_moved";
540    Extra quic::transport::MigrationStateUpdated     => urn "quic:migration_state_updated";
541    Base  quic::security::KeyUpdated                 => urn "quic:key_updated";
542    Base  quic::security::KeyDiscarded               => urn "quic:key_discarded";
543    Base  quic::recovery::RecoveryParametersSet      => urn "quic:recovery_parameters_set";
544    Core  quic::recovery::RecoveryMetricsUpdated     => urn "quic:recovery_metrics_updated";
545    Base  quic::recovery::CongestionStateUpdated     => urn "quic:congestion_state_updated";
546    Extra quic::recovery::LossTimerUpdated           => urn "quic:loss_timer_updated";
547    Core  quic::recovery::PacketLost                 => urn "quic:packet_lost";
548    Extra quic::recovery::MarkedForRetransmit        => urn "quic:marked_for_retransmit";
549    Extra quic::recovery::ECNStateUpdated            => urn "quic:ecn_state_updated";
550    Core  loglevel::Error                            => urn "loglevel:error";
551    Base  loglevel::Warning                          => urn "loglevel:warning";
552    Extra loglevel::Info                             => urn "loglevel:info";
553    Extra loglevel::Debug                            => urn "loglevel:debug";
554    Extra loglevel::Verbose                          => urn "loglevel:verbose";
555}
556
557/// serialize/deserialize as hex string, but store as bytes in memory
558#[serde_with::serde_as]
559#[derive(Debug, Clone, From, Into, Serialize, Deserialize, PartialEq, Eq)]
560#[serde(transparent)]
561pub struct HexString(#[serde_as(as = "serde_with::hex::Hex")] Bytes);
562
563impl Display for HexString {
564    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
565        write!(f, "{:x}", self.0)
566    }
567}
568
569#[serde_with::skip_serializing_none]
570#[derive(Builder, Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
571#[builder(
572    default,
573    setter(into, strip_option),
574    build_fn(private, name = "fallible_build")
575)]
576pub struct RawInfo {
577    /// the full byte length of the entity (e.g., packet or frame),
578    /// including possible headers and trailers
579    length: Option<u64>,
580    /// the byte length of the entity's payload,
581    /// excluding possible headers or trailers
582    payload_length: Option<u64>,
583    /// the (potentially truncated) contents of the full entity,
584    /// including headers and possibly trailers
585    #[builder(setter(custom))]
586    data: Option<HexString>,
587}
588
589impl RawInfoBuilder {
590    /// the (potentially truncated) contents of the full entity,
591    /// including headers and possibly trailers
592    pub fn data<D: ContinuousData>(&mut self, data: D) -> &mut Self {
593        self.data = telemetry::filter::raw_data().then(|| Some(data.to_bytes().into()));
594        self
595    }
596}
597
598impl<D: ContinuousData> From<D> for RawInfo {
599    fn from(data: D) -> Self {
600        build!(RawInfo {
601            length: data.len() as u64,
602            data: data
603        })
604    }
605}
606
607/// ``` rust, ignore
608/// crate::gen_builder_method! {
609///     FooBuilder       => Foo;
610///     BarBuilder       => Bar;
611/// }
612/// ```
613#[doc(hidden)]
614#[macro_export] // used in this crate only
615macro_rules! gen_builder_method {
616    ( $($builder:ty => $event:ty;)* ) => {
617        $( $crate::gen_builder_method!{@impl_one $event => $builder ;} )*
618    };
619    (@impl_one $event:ty => $builder:ty ; ) => {
620        impl $event {
621            pub fn builder() -> $builder {
622                Default::default()
623            }
624        }
625
626        impl $builder {
627            pub fn build(&mut self) -> $event {
628                self.fallible_build().expect("Failed to build event")
629            }
630        }
631    };
632}
633
634gen_builder_method! {
635    LogFileBuilder       => LogFile;
636    QlogFileBuilder      => QlogFile;
637    QlogFileSeqBuilder   => QlogFileSeq;
638    TraceBuilder         => Trace;
639    TraceSeqBuilder      => TraceSeq;
640    TraceErrorBuilder    => TraceError;
641    CommonFieldsBuilder  => CommonFields;
642    VantagePointBuilder  => VantagePoint;
643    EventBuilder         => Event;
644    ReferenceTimeBuilder => ReferenceTime;
645    RawInfoBuilder       => RawInfo;
646}
647
648mod rollback {
649
650    use super::*;
651    use crate::{build, legacy};
652
653    impl TryFrom<EvnetData> for legacy::EventData {
654        type Error = ();
655        #[rustfmt::skip]
656        fn try_from(value: EvnetData) -> Result<Self, Self::Error> {
657            match value {
658                EvnetData::ServerListening(data) => Ok(legacy::EventData::ServerListening(data.into())),
659                EvnetData::ConnectionStarted(data) => Ok(legacy::EventData::ConnectionStarted(data.into())),
660                EvnetData::ConnectionClosed(data) => Ok(legacy::EventData::ConnectionClosed(data.into())),
661                EvnetData::ConnectionIdUpdated(data) => Ok(legacy::EventData::ConnectionIdUpdated(data.into())),
662                EvnetData::SpinBitUpdated(data) => Ok(legacy::EventData::SpinBitUpdated(data.into())),
663                EvnetData::ConnectionStateUpdated(data) => Ok(legacy::EventData::ConnectionStateUpdated(data.into())),
664                EvnetData::PathAssigned(_data) => Err(()),
665                EvnetData::MtuUpdated(_data) => Err(()),
666                EvnetData::VersionInformation(data) => Ok(legacy::EventData::VersionInformation(data.into())),
667                EvnetData::ALPNInformation(data) => Ok(legacy::EventData::AlpnInformation(data.into())),
668                EvnetData::ParametersSet(data) => Ok(legacy::EventData::TransportParametersSet(data.into())),
669                EvnetData::ParametersRestored(data) => Ok(legacy::EventData::TransportParametersRestored(data.into())),
670                EvnetData::PacketSent(data) => Ok(legacy::EventData::PacketSent(data.into())),
671                EvnetData::PacketReceived(data) => Ok(legacy::EventData::PacketReceived(data.into())),
672                EvnetData::PacketDropped(data) => Ok(legacy::EventData::PacketDropped(data.into())),
673                EvnetData::PacketBuffered(data) => Ok(legacy::EventData::PacketBuffered(data.into())),
674                EvnetData::PacketsAcked(data) => Ok(legacy::EventData::PacketsAcked(data.into())),
675                EvnetData::UdpDatagramSent(data) => Ok(legacy::EventData::DatagramsSent(data.into())),
676                EvnetData::UdpDatagramReceived(data) => Ok(legacy::EventData::DatagramsReceived(data.into())),
677                EvnetData::UdpDatagramDropped(data) => Ok(legacy::EventData::DatagramDropped(data.into())),
678                EvnetData::StreamStateUpdated(data) => Ok(legacy::EventData::StreamStateUpdated(data.into())),
679                EvnetData::FramesProcessed(data) => Ok(legacy::EventData::FramesProcessed(data.into())),
680                EvnetData::StreamDataMoved(data) => Ok(legacy::EventData::DataMoved(data.into())),
681                EvnetData::DatagramDataMoved(_data) => Err(()),
682                EvnetData::MigrationStateUpdated(_data) => Err(()),
683                EvnetData::KeyUpdated(data) => Ok(legacy::EventData::KeyUpdated(data.into())),
684                EvnetData::KeyDiscarded(data) => Ok(legacy::EventData::KeyDiscarded(data.into())),
685                EvnetData::RecoveryParametersSet(data) => Ok(legacy::EventData::RecoveryParametersSet(data.into())),
686                EvnetData::RecoveryMetricsUpdated(data) => Ok(legacy::EventData::MetricsUpdated(data.into())),
687                EvnetData::CongestionStateUpdated(data) => Ok(legacy::EventData::CongestionStateUpdated(data.into())),
688                EvnetData::LossTimerUpdated(data) => Ok(legacy::EventData::LossTimerUpdated(data.into())),
689                EvnetData::PacketLost(data) => Ok(legacy::EventData::PacketLost(data.into())),
690                EvnetData::MarkedForRetransmit(data) => Ok(legacy::EventData::MarkedForRetransmit(data.into())),
691                EvnetData::ECNStateUpdated(_data) => Err(()),
692                EvnetData::Error(data) => Ok(legacy::EventData::GenericError(data.into())),
693                EvnetData::Warning(data) => Ok(legacy::EventData::GenericWarning(data.into())),
694                EvnetData::Info(data) => Ok(legacy::EventData::GenericInfo(data.into())),
695                EvnetData::Debug(data) => Ok(legacy::EventData::GenericDebug(data.into())),
696                EvnetData::Verbose(data) => Ok(legacy::EventData::GenericVerbose(data.into())),
697            }
698        }
699    }
700
701    impl From<TimeFormat> for legacy::TimeFormat {
702        fn from(value: TimeFormat) -> Self {
703            match value {
704                // note: depending on reference_time
705                //TOOD: check reference_time here
706                TimeFormat::RelativeToEpoch => legacy::TimeFormat::Absolute,
707                TimeFormat::RelativeToPreviousEvent => legacy::TimeFormat::Delta,
708            }
709        }
710    }
711
712    impl From<ProtocolTypeList> for legacy::ProtocolType {
713        fn from(value: ProtocolTypeList) -> Self {
714            value
715                .0
716                .into_iter()
717                .map(|x| x.into())
718                .collect::<Vec<_>>()
719                .into()
720        }
721    }
722
723    impl TryFrom<Event> for legacy::Event {
724        type Error = ();
725        fn try_from(mut event: Event) -> Result<Self, Self::Error> {
726            if let Some(system_info) = event.system_info {
727                let value = serde_json::to_value(system_info).unwrap();
728                event.custom_fields.insert("system_info".to_owned(), value);
729            }
730            if let Some(path) = event.path {
731                let value = serde_json::to_value(path).unwrap();
732                event.custom_fields.insert("path".to_owned(), value);
733            }
734            Ok(build!(legacy::Event {
735                time: event.time,
736                data: { legacy::EventData::try_from(event.data)? },
737                ?time_format: event.time_format,
738                ?protocol_type: event.protocol_types,
739                ?group_id: event.group_id,
740                custom_fields: event.custom_fields
741            }))
742        }
743    }
744}
745
746#[cfg(test)]
747mod tests {
748    use std::sync::Arc;
749
750    use qbase::cid::ConnectionId;
751
752    use super::*;
753    use crate::{loglevel::Warning, quic::connectivity::ConnectionStarted, telemetry::ExportEvent};
754
755    #[test]
756    fn custom_fields() {
757        let odcid = ConnectionID::from(ConnectionId::from_slice(&[
758            0x61, 0xb6, 0x91, 0x78, 0x80, 0xf7, 0x95, 0xee,
759        ]));
760        let common_fields = build!(CommonFields {
761            path: "".to_owned(),
762            time_format: TimeFormat::default(),
763            reference_time: ReferenceTime::default(),
764            protocol_types: ProtocolTypeList::from(vec![ProtocolType::quic()]),
765            group_id: GroupID::from(odcid),
766        });
767        let expect = r#"{
768  "path": "",
769  "time_format": "relative_to_epoch",
770  "reference_time": {
771    "clock_type": "system",
772    "epoch": "1970-01-01T00:00:00.000Z"
773  },
774  "protocol_types": [
775    "QUIC"
776  ],
777  "group_id": "61b6917880f795ee"
778}"#;
779        assert_eq!(
780            serde_json::to_string_pretty(&common_fields).unwrap(),
781            expect
782        );
783        let with_custom_fields = r#"{
784  "path": "",
785  "time_format": "relative_to_epoch",
786  "reference_time": {
787    "clock_type": "system",
788    "epoch": "1970-01-01T00:00:00.000Z"
789  },
790  "protocol_types": [
791    "QUIC"
792  ],
793  "group_id": "61b6917880f795ee",
794  "pathway": "from A to relay",
795  "customB": "some other extensions"
796}"#;
797        let des = serde_json::from_str::<CommonFields>(with_custom_fields).unwrap();
798        let filed_string = serde_json::to_string_pretty(&des).unwrap();
799        let des2 = serde_json::from_str::<CommonFields>(&filed_string).unwrap();
800        assert_eq!(des, des2);
801    }
802
803    #[test]
804    fn evnet_data() {
805        let data = EvnetData::from(build!(Warning {
806            message: "deepseek(已深度思考(用时0秒)):服务器繁忙,请稍后再试。",
807            code: 255u64,
808        }));
809        let event = build!(Event {
810            time: 1.0,
811            data: data.clone(),
812        });
813        let expect = r#"{
814  "time": 1.0,
815  "name": "loglevel:warning",
816  "data": {
817    "code": 255,
818    "message": "deepseek(已深度思考(用时0秒)):服务器繁忙,请稍后再试。"
819  }
820}"#;
821        assert_eq!(serde_json::to_string_pretty(&event).unwrap(), expect);
822        assert_eq!(data.importance(), EventImportance::Base);
823    }
824
825    #[test]
826    fn rollback() {
827        fn group_id() -> GroupID {
828            GroupID::from(ConnectionID::from(ConnectionId::from_slice(&[
829                0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x32,
830            ])))
831        }
832
833        fn protocol_types() -> Vec<String> {
834            vec!["QUIC".to_owned(), "UNKNOW".to_owned()]
835        }
836
837        struct TestBroker;
838
839        impl ExportEvent for TestBroker {
840            fn emit(&self, event: Event) {
841                let legacy = legacy::Event::try_from(event).unwrap();
842                let event = serde_json::to_value(legacy).unwrap();
843
844                let data = serde_json::json!({
845                    "ip_version": "v4",
846                    "src_ip": "127.0.0.1",
847                    "dst_ip": "192.168.31.1",
848                    "protocol": "QUIC",
849                    "src_port": 23456,
850                    "dst_port": 21
851                });
852                // in 10: this callde protocol_types
853                let protocol_type = serde_json::json!(["QUIC", "UNKNOW"]);
854
855                assert_eq!(event["data"], data);
856                assert_eq!(event["protocol_types"], serde_json::Value::Null);
857                assert_eq!(event["protocol_type"], protocol_type);
858                assert_eq!(event["to_router"], true);
859            }
860        }
861
862        span!(
863            Arc::new(TestBroker),
864            group_id = group_id(),
865            protocol_types = protocol_types()
866        )
867        .in_scope(|| {
868            let src = "127.0.0.1:23456".parse().unwrap();
869            let dst = "192.168.31.1:21".parse().unwrap();
870            event!(ConnectionStarted { socket: (src, dst) }, to_router = true)
871        })
872    }
873}