// Copyright (C) 2020, Cloudflare, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //! Module-defined Event and functions to work with qlog data structures. //! //! The Qlog data structures are very flexible, which makes working with them //! liable to simple semantic errors. This module provides some helper functions //! that focus on creating valid types, while also reducing some of the //! verbosity of using the raw data structures. use super::*; /// A representation of qlog events that couple EventCategory, EventType and /// EventData. /// /// Functions are provided to help construct valid events. Most events consist /// of several optional fields, so minimal versions of these functions are /// provided, which accept only mandatory qlog parameters. Minimal functions are /// identified by a `_min` suffix. #[derive(Clone)] pub struct Event { pub category: EventCategory, pub ty: EventType, pub data: EventData, } #[allow(clippy::too_many_arguments)] impl Event { // Connectivity events. /// Returns: /// * `EventCategory`=`Connectivity` /// * `EventType`=`ConnectivityEventType::ServerListening` /// * `EventData`=`ServerListening`. pub fn server_listening( ip_v4: Option, ip_v6: Option, port_v4: u64, port_v6: u64, quic_versions: Option>, alpn_values: Option>, stateless_reset_required: Option, ) -> Self { Event { category: EventCategory::Connectivity, ty: EventType::ConnectivityEventType( ConnectivityEventType::ServerListening, ), data: EventData::ServerListening { ip_v4, ip_v6, port_v4, port_v6, quic_versions, alpn_values, stateless_reset_required, }, } } pub fn server_listening_min(port_v4: u64, port_v6: u64) -> Self { Event::server_listening(None, None, port_v4, port_v6, None, None, None) } /// Returns: /// * `EventCategory`=`Connectivity` /// * `EventType`=`ConnectivityEventType::ConnectionStarted` /// * `EventData`=`ConnectionStarted`. pub fn connection_started( ip_version: String, src_ip: String, dst_ip: String, protocol: Option, src_port: u64, dst_port: u64, quic_version: Option, src_cid: Option, dst_cid: Option, ) -> Self { Event { category: EventCategory::Connectivity, ty: EventType::ConnectivityEventType( ConnectivityEventType::ConnectionStarted, ), data: EventData::ConnectionStarted { ip_version, src_ip, dst_ip, protocol, src_port, dst_port, quic_version, src_cid, dst_cid, }, } } pub fn connection_started_min( ip_version: String, src_ip: String, dst_ip: String, src_port: u64, dst_port: u64, ) -> Self { Event::connection_started( ip_version, src_ip, dst_ip, None, src_port, dst_port, None, None, None, ) } /// Returns: /// * `EventCategory`=`Connectivity` /// * `EventType`=`ConnectivityEventType::ConnectionIdUpdated` /// * `EventData`=`ConnectionIdUpdated`. pub fn connection_id_updated( src_old: Option, src_new: Option, dst_old: Option, dst_new: Option, ) -> Self { Event { category: EventCategory::Connectivity, ty: EventType::ConnectivityEventType( ConnectivityEventType::ConnectionIdUpdated, ), data: EventData::ConnectionIdUpdated { src_old, src_new, dst_old, dst_new, }, } } pub fn connection_id_updated_min() -> Self { Event::connection_id_updated(None, None, None, None) } /// Returns: /// * `EventCategory`=`Connectivity` /// * `EventType`=`ConnectivityEventType::SpinBitUpdated` /// * `EventData`=`SpinBitUpdated`. pub fn spinbit_updated(state: bool) -> Self { Event { category: EventCategory::Connectivity, ty: EventType::ConnectivityEventType( ConnectivityEventType::SpinBitUpdated, ), data: EventData::SpinBitUpdated { state }, } } /// Returns: /// * `EventCategory`=`Connectivity` /// * `EventType`=`ConnectivityEventType::ConnectionState` /// * `EventData`=`ConnectionState`. pub fn connection_state_updated( old: Option, new: ConnectionState, ) -> Self { Event { category: EventCategory::Connectivity, ty: EventType::ConnectivityEventType( ConnectivityEventType::ConnectionStateUpdated, ), data: EventData::ConnectionStateUpdated { old, new }, } } pub fn connection_state_updated_min(new: ConnectionState) -> Self { Event::connection_state_updated(None, new) } // Transport events. /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::ParametersSet` /// * `EventData`=`ParametersSet`. pub fn transport_parameters_set( owner: Option, resumption_allowed: Option, early_data_enabled: Option, alpn: Option, version: Option, tls_cipher: Option, original_connection_id: Option, stateless_reset_token: Option, disable_active_migration: Option, idle_timeout: Option, max_packet_size: Option, ack_delay_exponent: Option, max_ack_delay: Option, active_connection_id_limit: Option, initial_max_data: Option, initial_max_stream_data_bidi_local: Option, initial_max_stream_data_bidi_remote: Option, initial_max_stream_data_uni: Option, initial_max_streams_bidi: Option, initial_max_streams_uni: Option, preferred_address: Option, ) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType(TransportEventType::ParametersSet), data: EventData::TransportParametersSet { owner, resumption_allowed, early_data_enabled, alpn, version, tls_cipher, original_connection_id, stateless_reset_token, disable_active_migration, idle_timeout, max_packet_size, ack_delay_exponent, max_ack_delay, active_connection_id_limit, initial_max_data, initial_max_stream_data_bidi_local, initial_max_stream_data_bidi_remote, initial_max_stream_data_uni, initial_max_streams_bidi, initial_max_streams_uni, preferred_address, }, } } pub fn transport_parameters_set_min() -> Self { Event::transport_parameters_set( None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::DatagramsReceived` /// * `EventData`=`DatagramsReceived`. pub fn datagrams_received( count: Option, byte_length: Option, ) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType( TransportEventType::DatagramsReceived, ), data: EventData::DatagramsReceived { count, byte_length }, } } pub fn datagrams_received_min() -> Self { Event::datagrams_received(None, None) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::DatagramsSent` /// * `EventData`=`DatagramsSent`. pub fn datagrams_sent(count: Option, byte_length: Option) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType(TransportEventType::DatagramsSent), data: EventData::DatagramsSent { count, byte_length }, } } pub fn datagrams_sent_min() -> Self { Event::datagrams_sent(None, None) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::DatagramDropped` /// * `EventData`=`DatagramDropped`. pub fn datagram_dropped(byte_length: Option) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType( TransportEventType::DatagramDropped, ), data: EventData::DatagramDropped { byte_length }, } } pub fn datagram_dropped_min() -> Self { Event::datagram_dropped(None) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::PacketReceived` /// * `EventData`=`PacketReceived`. pub fn packet_received( packet_type: PacketType, header: PacketHeader, frames: Option>, is_coalesced: Option, raw_encrypted: Option, raw_decrypted: Option, ) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType(TransportEventType::PacketReceived), data: EventData::PacketReceived { packet_type, header, frames, is_coalesced, raw_encrypted, raw_decrypted, }, } } pub fn packet_received_min( packet_type: PacketType, header: PacketHeader, ) -> Self { Event::packet_received(packet_type, header, None, None, None, None) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::PacketSent` /// * `EventData`=`PacketSent`. pub fn packet_sent( packet_type: PacketType, header: PacketHeader, frames: Option>, is_coalesced: Option, raw_encrypted: Option, raw_decrypted: Option, ) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType(TransportEventType::PacketSent), data: EventData::PacketSent { packet_type, header, frames, is_coalesced, raw_encrypted, raw_decrypted, }, } } pub fn packet_sent_min( packet_type: PacketType, header: PacketHeader, frames: Option>, ) -> Self { Event::packet_sent(packet_type, header, frames, None, None, None) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::PacketDropped` /// * `EventData`=`PacketDropped`. pub fn packet_dropped( packet_type: Option, packet_size: Option, raw: Option, ) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType(TransportEventType::PacketDropped), data: EventData::PacketDropped { packet_type, packet_size, raw, }, } } pub fn packet_dropped_min() -> Self { Event::packet_dropped(None, None, None) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::PacketBuffered` /// * `EventData`=`PacketBuffered`. pub fn packet_buffered( packet_type: PacketType, packet_number: String, ) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType(TransportEventType::PacketBuffered), data: EventData::PacketBuffered { packet_type, packet_number, }, } } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::StreamStateUpdated` /// * `EventData`=`StreamStateUpdated`. pub fn stream_state_updated( stream_id: String, stream_type: Option, old: Option, new: StreamState, stream_side: Option, ) -> Self { Event { category: EventCategory::Connectivity, ty: EventType::TransportEventType( TransportEventType::StreamStateUpdated, ), data: EventData::StreamStateUpdated { stream_id, stream_type, old, new, stream_side, }, } } pub fn stream_state_updated_min(stream_id: String, new: StreamState) -> Self { Event::stream_state_updated(stream_id, None, None, new, None) } /// Returns: /// * `EventCategory`=`Transport` /// * `EventType`=`TransportEventType::FramesProcessed` /// * `EventData`=`FramesProcessed`. pub fn frames_processed(frames: Vec) -> Self { Event { category: EventCategory::Transport, ty: EventType::TransportEventType( TransportEventType::FramesProcessed, ), data: EventData::FramesProcessed { frames }, } } // Recovery events. /// Returns: /// * `EventCategory`=`Recovery` /// * `EventType`=`RecoveryEventType::ParametersSet` /// * `EventData`=`RecoveryParametersSet`. pub fn recovery_parameters_set( reordering_threshold: Option, time_threshold: Option, timer_granularity: Option, initial_rtt: Option, max_datagram_size: Option, initial_congestion_window: Option, minimum_congestion_window: Option, loss_reduction_factor: Option, persistent_congestion_threshold: Option, ) -> Self { Event { category: EventCategory::Recovery, ty: EventType::RecoveryEventType(RecoveryEventType::ParametersSet), data: EventData::RecoveryParametersSet { reordering_threshold, time_threshold, timer_granularity, initial_rtt, max_datagram_size, initial_congestion_window, minimum_congestion_window, loss_reduction_factor, persistent_congestion_threshold, }, } } pub fn recovery_parameters_set_min() -> Self { Event::recovery_parameters_set( None, None, None, None, None, None, None, None, None, ) } /// Returns: /// * `EventCategory`=`Recovery` /// * `EventType`=`RecoveryEventType::MetricsUpdated` /// * `EventData`=`MetricsUpdated`. pub fn metrics_updated( min_rtt: Option, smoothed_rtt: Option, latest_rtt: Option, rtt_variance: Option, max_ack_delay: Option, pto_count: Option, congestion_window: Option, bytes_in_flight: Option, ssthresh: Option, packets_in_flight: Option, in_recovery: Option, pacing_rate: Option, ) -> Self { Event { category: EventCategory::Recovery, ty: EventType::RecoveryEventType(RecoveryEventType::MetricsUpdated), data: EventData::MetricsUpdated { min_rtt, smoothed_rtt, latest_rtt, rtt_variance, max_ack_delay, pto_count, congestion_window, bytes_in_flight, ssthresh, packets_in_flight, in_recovery, pacing_rate, }, } } pub fn metrics_updated_min() -> Self { Event::metrics_updated( None, None, None, None, None, None, None, None, None, None, None, None, ) } /// Returns: /// * `EventCategory`=`Recovery` /// * `EventType`=`RecoveryEventType::CongestionStateUpdated` /// * `EventData`=`CongestionStateUpdated`. pub fn congestion_state_updated(old: Option, new: String) -> Self { Event { category: EventCategory::Recovery, ty: EventType::RecoveryEventType( RecoveryEventType::CongestionStateUpdated, ), data: EventData::CongestionStateUpdated { old, new }, } } pub fn congestion_state_updated_min(new: String) -> Self { Event::congestion_state_updated(None, new) } /// Returns: /// * `EventCategory`=`Recovery` /// * `EventType`=`RecoveryEventType::LossTimerSet` /// * `EventData`=`LossTimerSet`. pub fn loss_timer_set( timer_type: Option, timeout: Option, ) -> Self { Event { category: EventCategory::Recovery, ty: EventType::RecoveryEventType(RecoveryEventType::LossTimerSet), data: EventData::LossTimerSet { timer_type, timeout, }, } } pub fn loss_timer_set_min() -> Self { Event::loss_timer_set(None, None) } /// Returns: /// * `EventCategory`=`Recovery` /// * `EventType`=`RecoveryEventType::PacketLost` /// * `EventData`=`PacketLost`. pub fn packet_lost( packet_type: PacketType, packet_number: String, header: Option, frames: Vec, ) -> Self { Event { category: EventCategory::Recovery, ty: EventType::RecoveryEventType(RecoveryEventType::PacketLost), data: EventData::PacketLost { packet_type, packet_number, header, frames, }, } } pub fn packet_lost_min( packet_type: PacketType, packet_number: String, frames: Vec, ) -> Self { Event::packet_lost(packet_type, packet_number, None, frames) } /// Returns: /// * `EventCategory`=`Recovery` /// * `EventType`=`RecoveryEventType::MarkedForRetransmit` /// * `EventData`=`MarkedForRetransmit`. pub fn marked_for_retransmit(frames: Vec) -> Self { Event { category: EventCategory::Recovery, ty: EventType::RecoveryEventType( RecoveryEventType::MarkedForRetransmit, ), data: EventData::MarkedForRetransmit { frames }, } } // HTTP/3 events. /// Returns: /// * `EventCategory`=`Http` /// * `EventType`=`Http3EventType::ParametersSet` /// * `EventData`=`H3ParametersSet`. pub fn h3_parameters_set( owner: Option, max_header_list_size: Option, max_table_capacity: Option, blocked_streams_count: Option, push_allowed: Option, waits_for_settings: Option, ) -> Self { Event { category: EventCategory::Http, ty: EventType::Http3EventType(Http3EventType::ParametersSet), data: EventData::H3ParametersSet { owner, max_header_list_size, max_table_capacity, blocked_streams_count, push_allowed, waits_for_settings, }, } } pub fn h3_parameters_set_min() -> Self { Event::h3_parameters_set(None, None, None, None, None, None) } /// Returns: /// * `EventCategory`=`Http` /// * `EventType`=`Http3EventType::StreamTypeSet` /// * `EventData`=`H3StreamTypeSet`. pub fn h3_stream_type_set( stream_id: String, owner: Option, old: Option, new: H3StreamType, ) -> Self { Event { category: EventCategory::Http, ty: EventType::Http3EventType(Http3EventType::StreamTypeSet), data: EventData::H3StreamTypeSet { stream_id, owner, old, new, }, } } pub fn h3_stream_type_set_min(stream_id: String, new: H3StreamType) -> Self { Event::h3_stream_type_set(stream_id, None, None, new) } /// Returns: /// * `EventCategory`=`Http` /// * `EventType`=`Http3EventType::FrameCreated` /// * `EventData`=`H3FrameCreated`. pub fn h3_frame_created( stream_id: String, frame: Http3Frame, byte_length: Option, raw: Option, ) -> Self { Event { category: EventCategory::Http, ty: EventType::Http3EventType(Http3EventType::FrameCreated), data: EventData::H3FrameCreated { stream_id, frame, byte_length, raw, }, } } pub fn h3_frame_created_min(stream_id: String, frame: Http3Frame) -> Self { Event::h3_frame_created(stream_id, frame, None, None) } /// Returns: /// * `EventCategory`=`Http` /// * `EventType`=`Http3EventType::FrameParsed` /// * `EventData`=`H3FrameParsed`. pub fn h3_frame_parsed( stream_id: String, frame: Http3Frame, byte_length: Option, raw: Option, ) -> Self { Event { category: EventCategory::Http, ty: EventType::Http3EventType(Http3EventType::FrameParsed), data: EventData::H3FrameParsed { stream_id, frame, byte_length, raw, }, } } pub fn h3_frame_parsed_min(stream_id: String, frame: Http3Frame) -> Self { Event::h3_frame_parsed(stream_id, frame, None, None) } /// Returns: /// * `EventCategory`=`Http` /// * `EventType`=`Http3EventType::DataMoved` /// * `EventData`=`H3DataMoved`. pub fn h3_data_moved( stream_id: String, offset: Option, length: Option, from: Option, to: Option, raw: Option, ) -> Self { Event { category: EventCategory::Http, ty: EventType::Http3EventType(Http3EventType::DataMoved), data: EventData::H3DataMoved { stream_id, offset, length, from, to, raw, }, } } pub fn h3_data_moved_min(stream_id: String) -> Self { Event::h3_data_moved(stream_id, None, None, None, None, None) } /// Returns: /// * `EventCategory`=`Http` /// * `EventType`=`Http3EventType::PushResolved` /// * `EventData`=`H3PushResolved`. pub fn h3_push_resolved( push_id: Option, stream_id: Option, decision: Option, ) -> Self { Event { category: EventCategory::Http, ty: EventType::Http3EventType(Http3EventType::PushResolved), data: EventData::H3PushResolved { push_id, stream_id, decision, }, } } pub fn h3_push_resolved_min() -> Self { Event::h3_push_resolved(None, None, None) } // QPACK events. /// Returns: /// * `EventCategory`=`Qpack` /// * `EventType`=`QpackEventType::StateUpdated` /// * `EventData`=`QpackStateUpdated`. pub fn qpack_state_updated( owner: Option, dynamic_table_capacity: Option, dynamic_table_size: Option, known_received_count: Option, current_insert_count: Option, ) -> Self { Event { category: EventCategory::Qpack, ty: EventType::QpackEventType(QpackEventType::StateUpdated), data: EventData::QpackStateUpdated { owner, dynamic_table_capacity, dynamic_table_size, known_received_count, current_insert_count, }, } } pub fn qpack_state_updated_min() -> Self { Event::qpack_state_updated(None, None, None, None, None) } /// Returns: /// * `EventCategory`=`Qpack` /// * `EventType`=`QpackEventType::StreamStateUpdated` /// * `EventData`=`QpackStreamStateUpdated`. pub fn qpack_stream_state_updated( stream_id: String, state: QpackStreamState, ) -> Self { Event { category: EventCategory::Qpack, ty: EventType::QpackEventType(QpackEventType::StreamStateUpdated), data: EventData::QpackStreamStateUpdated { stream_id, state }, } } /// Returns: /// * `EventCategory`=`Qpack` /// * `EventType`=`QpackEventType::DynamicTableUpdated` /// * `EventData`=`QpackDynamicTableUpdated`. pub fn qpack_dynamic_table_updated( update_type: QpackUpdateType, entries: Vec, ) -> Self { Event { category: EventCategory::Qpack, ty: EventType::QpackEventType(QpackEventType::DynamicTableUpdated), data: EventData::QpackDynamicTableUpdated { update_type, entries, }, } } /// Returns: /// * `EventCategory`=`Qpack` /// * `EventType`=`QpackEventType::HeadersEncoded` /// * `EventData`=`QpackHeadersEncoded`. pub fn qpack_headers_encoded( stream_id: Option, headers: Option, block_prefix: QpackHeaderBlockPrefix, header_block: Vec, raw: Option, ) -> Self { Event { category: EventCategory::Qpack, ty: EventType::QpackEventType(QpackEventType::HeadersEncoded), data: EventData::QpackHeadersEncoded { stream_id, headers, block_prefix, header_block, raw, }, } } pub fn qpack_headers_encoded_min( block_prefix: QpackHeaderBlockPrefix, header_block: Vec, ) -> Self { Event::qpack_headers_encoded(None, None, block_prefix, header_block, None) } /// Returns: /// * `EventCategory`=`Qpack` /// * `EventType`=`QpackEventType::HeadersDecoded` /// * `EventData`=`QpackHeadersDecoded`. pub fn qpack_headers_decoded( stream_id: Option, headers: Option, block_prefix: QpackHeaderBlockPrefix, header_block: Vec, raw: Option, ) -> Self { Event { category: EventCategory::Qpack, ty: EventType::QpackEventType(QpackEventType::HeadersDecoded), data: EventData::QpackHeadersDecoded { stream_id, headers, block_prefix, header_block, raw, }, } } pub fn qpack_headers_decoded_min( block_prefix: QpackHeaderBlockPrefix, header_block: Vec, ) -> Self { Event::qpack_headers_decoded(None, None, block_prefix, header_block, None) } /// Returns: /// * `EventCategory`=`Qpack` /// * `EventType`=`QpackEventType::InstructionSent` /// * `EventData`=`QpackInstructionSent`. pub fn qpack_instruction_sent( instruction: QPackInstruction, byte_length: Option, raw: Option, ) -> Self { Event { category: EventCategory::Qpack, ty: EventType::QpackEventType(QpackEventType::InstructionSent), data: EventData::QpackInstructionSent { instruction, byte_length, raw, }, } } pub fn qpack_instruction_sent_min(instruction: QPackInstruction) -> Self { Event::qpack_instruction_sent(instruction, None, None) } /// Returns: /// * `EventCategory`=`Qpack` /// * `EventType`=`QpackEventType::InstructionReceived` /// * `EventData`=`QpackInstructionReceived`. pub fn qpack_instruction_received( instruction: QPackInstruction, byte_length: Option, raw: Option, ) -> Self { Event { category: EventCategory::Qpack, ty: EventType::QpackEventType(QpackEventType::InstructionReceived), data: EventData::QpackInstructionReceived { instruction, byte_length, raw, }, } } pub fn qpack_instruction_received_min(instruction: QPackInstruction) -> Self { Event::qpack_instruction_received(instruction, None, None) } /// Checks if the the combination of `EventCategory`, `EventType` and /// `EventData` is valid. pub fn is_valid(&self) -> bool { match (&self.category, &self.ty) { ( EventCategory::Connectivity, EventType::ConnectivityEventType(_), ) => matches!(&self.data, EventData::ServerListening { .. } | EventData::ConnectionStarted { .. } | EventData::ConnectionIdUpdated { .. } | EventData::SpinBitUpdated { .. } | EventData::ConnectionStateUpdated { .. }), (EventCategory::Transport, EventType::TransportEventType(_)) => matches!(&self.data, EventData::TransportParametersSet { .. } | EventData::DatagramsReceived { .. } | EventData::DatagramsSent { .. } | EventData::DatagramDropped { .. } | EventData::PacketReceived { .. } | EventData::PacketSent { .. } | EventData::PacketDropped { .. } | EventData::PacketBuffered { .. } | EventData::StreamStateUpdated { .. } | EventData::FramesProcessed { .. }), (EventCategory::Security, EventType::SecurityEventType(_)) => matches!(&self.data, EventData::KeyUpdated { .. } | EventData::KeyRetired { .. }), (EventCategory::Recovery, EventType::RecoveryEventType(_)) => matches!(&self.data, EventData::RecoveryParametersSet { .. } | EventData::MetricsUpdated { .. } | EventData::CongestionStateUpdated { .. } | EventData::LossTimerSet { .. } | EventData::PacketLost { .. } | EventData::MarkedForRetransmit { .. }), (EventCategory::Http, EventType::Http3EventType(_)) => matches!(&self.data, EventData::H3ParametersSet { .. } | EventData::H3StreamTypeSet { .. } | EventData::H3FrameCreated { .. } | EventData::H3FrameParsed { .. } | EventData::H3DataMoved { .. } | EventData::H3PushResolved { .. }), (EventCategory::Qpack, EventType::QpackEventType(_)) => matches!(&self.data, EventData::QpackStateUpdated { .. } | EventData::QpackStreamStateUpdated { .. } | EventData::QpackDynamicTableUpdated { .. } | EventData::QpackHeadersEncoded { .. } | EventData::QpackHeadersDecoded { .. } | EventData::QpackInstructionSent { .. } | EventData::QpackInstructionReceived { .. }), // TODO: in qlog-01 there is no sane default category defined for // GenericEventType (_, EventType::GenericEventType(_)) => matches!(&self.data, EventData::ConnectionError { .. } | EventData::ApplicationError { .. } | EventData::InternalError { .. } | EventData::InternalWarning { .. } | EventData::Message { .. } | EventData::Marker { .. }), _ => false, } } }