QUIC R. Marx, Ed. Internet-Draft Akamai Intended status: Standards Track L. Niccolini, Ed. Expires: 6 May 2027 Meta M. Seemann, Ed. L. Pardue, Ed. Apple 2 November 2026 QUIC event definitions for qlog draft-ietf-quic-qlog-quic-events-14 Abstract This document describes a qlog event schema containing concrete qlog event definitions and their metadata for the core QUIC protocol and selected extensions. Note to Readers Note to RFC editor: Please remove this section before publication. Feedback and discussion are welcome at https://github.com/quicwg/qlog (https://github.com/quicwg/qlog). Readers are advised to refer to the "editor's draft" at that URL for an up-to-date version of this document. Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 6 May 2027. Marx, et al. Expires 6 May 2027 [Page 1] Internet-Draft QUIC event definitions for qlog November 2026 Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1. Use of Group IDs . . . . . . . . . . . . . . . . . . . . 5 1.2. Raw Packet and Frame Information . . . . . . . . . . . . 5 1.3. Events without a Known Connection . . . . . . . . . . . . 5 1.4. Notational Conventions . . . . . . . . . . . . . . . . . 6 2. Event Schema Definition . . . . . . . . . . . . . . . . . . . 6 2.1. Draft Event Schema Identification . . . . . . . . . . . . 6 3. QUIC Event Overview . . . . . . . . . . . . . . . . . . . . . 7 4. Connectivity Events . . . . . . . . . . . . . . . . . . . . . 10 4.1. server_listening . . . . . . . . . . . . . . . . . . . . 10 4.2. connection_started . . . . . . . . . . . . . . . . . . . 10 4.3. connection_closed . . . . . . . . . . . . . . . . . . . . 11 4.4. connection_id_updated . . . . . . . . . . . . . . . . . . 12 4.5. spin_bit_updated . . . . . . . . . . . . . . . . . . . . 13 4.6. connection_state_updated . . . . . . . . . . . . . . . . 13 4.7. tuple_assigned . . . . . . . . . . . . . . . . . . . . . 15 4.8. mtu_updated . . . . . . . . . . . . . . . . . . . . . . . 16 5. Transport Events . . . . . . . . . . . . . . . . . . . . . . 16 5.1. version_information . . . . . . . . . . . . . . . . . . . 16 5.2. alpn_information . . . . . . . . . . . . . . . . . . . . 17 5.3. parameters_set . . . . . . . . . . . . . . . . . . . . . 18 5.4. parameters_restored . . . . . . . . . . . . . . . . . . . 20 5.5. packet_sent . . . . . . . . . . . . . . . . . . . . . . . 21 5.6. packet_received . . . . . . . . . . . . . . . . . . . . . 22 5.7. packet_dropped . . . . . . . . . . . . . . . . . . . . . 23 5.8. packet_buffered . . . . . . . . . . . . . . . . . . . . . 25 5.9. packets_acked . . . . . . . . . . . . . . . . . . . . . . 25 5.10. udp_datagrams_sent . . . . . . . . . . . . . . . . . . . 26 5.11. udp_datagrams_received . . . . . . . . . . . . . . . . . 27 5.12. udp_datagram_dropped . . . . . . . . . . . . . . . . . . 27 5.13. stream_state_updated . . . . . . . . . . . . . . . . . . 28 5.14. Frame-Related Events . . . . . . . . . . . . . . . . . . 30 Marx, et al. Expires 6 May 2027 [Page 2] Internet-Draft QUIC event definitions for qlog November 2026 5.14.1. frames_created . . . . . . . . . . . . . . . . . . . 31 5.14.2. frames_parsed . . . . . . . . . . . . . . . . . . . 31 5.15. stream_data_moved . . . . . . . . . . . . . . . . . . . . 31 5.16. datagram_data_moved . . . . . . . . . . . . . . . . . . . 32 5.17. datagram_dropped . . . . . . . . . . . . . . . . . . . . 33 5.18. connection_data_blocked_updated . . . . . . . . . . . . . 34 5.19. stream_data_blocked_updated . . . . . . . . . . . . . . . 35 5.20. datagram_data_blocked_updated . . . . . . . . . . . . . . 35 5.21. migration_state_updated . . . . . . . . . . . . . . . . . 35 5.22. timer_updated . . . . . . . . . . . . . . . . . . . . . . 37 6. Security Events . . . . . . . . . . . . . . . . . . . . . . . 38 6.1. key_updated . . . . . . . . . . . . . . . . . . . . . . . 38 6.2. key_discarded . . . . . . . . . . . . . . . . . . . . . . 39 7. Recovery Events . . . . . . . . . . . . . . . . . . . . . . . 40 7.1. recovery_parameters_set . . . . . . . . . . . . . . . . . 40 7.2. recovery_metrics_updated . . . . . . . . . . . . . . . . 41 7.3. congestion_state_updated . . . . . . . . . . . . . . . . 43 7.4. packet_lost . . . . . . . . . . . . . . . . . . . . . . . 43 7.5. marked_for_retransmit . . . . . . . . . . . . . . . . . . 44 7.6. ecn_state_updated . . . . . . . . . . . . . . . . . . . . 45 8. QUIC Data Type Definitions . . . . . . . . . . . . . . . . . 45 8.1. QuicVersion . . . . . . . . . . . . . . . . . . . . . . . 45 8.2. ConnectionID . . . . . . . . . . . . . . . . . . . . . . 46 8.3. Initiator . . . . . . . . . . . . . . . . . . . . . . . . 46 8.4. IPAddressPort . . . . . . . . . . . . . . . . . . . . . . 46 8.5. TupleEndpointInfo . . . . . . . . . . . . . . . . . . . . 46 8.6. PacketType . . . . . . . . . . . . . . . . . . . . . . . 47 8.7. PacketNumberSpace . . . . . . . . . . . . . . . . . . . . 47 8.8. PacketHeader . . . . . . . . . . . . . . . . . . . . . . 47 8.9. Token . . . . . . . . . . . . . . . . . . . . . . . . . . 49 8.10. StatelessResetToken . . . . . . . . . . . . . . . . . . . 49 8.11. KeyType . . . . . . . . . . . . . . . . . . . . . . . . . 49 8.12. ECN . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 8.13. QUIC Frames . . . . . . . . . . . . . . . . . . . . . . . 50 8.13.1. PaddingFrame . . . . . . . . . . . . . . . . . . . . 51 8.13.2. PingFrame . . . . . . . . . . . . . . . . . . . . . 51 8.13.3. AckFrame . . . . . . . . . . . . . . . . . . . . . . 52 8.13.4. ResetStreamFrame . . . . . . . . . . . . . . . . . . 52 8.13.5. ResetStreamAtFrame . . . . . . . . . . . . . . . . . 53 8.13.6. StopSendingFrame . . . . . . . . . . . . . . . . . . 53 8.13.7. CryptoFrame . . . . . . . . . . . . . . . . . . . . 54 8.13.8. NewTokenFrame . . . . . . . . . . . . . . . . . . . 54 8.13.9. StreamFrame . . . . . . . . . . . . . . . . . . . . 54 8.13.10. MaxDataFrame . . . . . . . . . . . . . . . . . . . . 55 8.13.11. MaxStreamDataFrame . . . . . . . . . . . . . . . . . 55 8.13.12. MaxStreamsFrame . . . . . . . . . . . . . . . . . . 55 8.13.13. DataBlockedFrame . . . . . . . . . . . . . . . . . . 55 8.13.14. StreamDataBlockedFrame . . . . . . . . . . . . . . . 56 Marx, et al. Expires 6 May 2027 [Page 3] Internet-Draft QUIC event definitions for qlog November 2026 8.13.15. StreamsBlockedFrame . . . . . . . . . . . . . . . . 56 8.13.16. NewConnectionIDFrame . . . . . . . . . . . . . . . . 56 8.13.17. RetireConnectionIDFrame . . . . . . . . . . . . . . 57 8.13.18. PathChallengeFrame . . . . . . . . . . . . . . . . . 57 8.13.19. PathResponseFrame . . . . . . . . . . . . . . . . . 57 8.13.20. ConnectionCloseFrame . . . . . . . . . . . . . . . . 57 8.13.21. HandshakeDoneFrame . . . . . . . . . . . . . . . . . 58 8.13.22. UnknownFrame . . . . . . . . . . . . . . . . . . . . 58 8.13.23. DatagramFrame . . . . . . . . . . . . . . . . . . . 59 8.14. TransportError . . . . . . . . . . . . . . . . . . . . . 59 8.15. ApplicationError . . . . . . . . . . . . . . . . . . . . 60 8.16. CryptoError . . . . . . . . . . . . . . . . . . . . . . . 60 9. Handling Packet Coalescing . . . . . . . . . . . . . . . . . 61 10. Security and Privacy Considerations . . . . . . . . . . . . . 61 11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 61 12. References . . . . . . . . . . . . . . . . . . . . . . . . . 62 12.1. Normative References . . . . . . . . . . . . . . . . . . 62 12.2. Informative References . . . . . . . . . . . . . . . . . 63 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 63 Change Log . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Since draft-ietf-qlog-quic-events-13: . . . . . . . . . . . . . 64 Since draft-ietf-qlog-quic-events-12: . . . . . . . . . . . . . 64 Since draft-ietf-qlog-quic-events-11: . . . . . . . . . . . . . 64 Since draft-ietf-qlog-quic-events-09: . . . . . . . . . . . . . 64 Since draft-ietf-qlog-quic-events-08: . . . . . . . . . . . . . 64 Since draft-ietf-qlog-quic-events-07: . . . . . . . . . . . . . 65 Since draft-ietf-qlog-quic-events-06: . . . . . . . . . . . . . 65 Since draft-ietf-qlog-quic-events-05: . . . . . . . . . . . . . 65 Since draft-ietf-qlog-quic-events-04: . . . . . . . . . . . . . 65 Since draft-ietf-qlog-quic-events-03: . . . . . . . . . . . . . 66 Since draft-ietf-qlog-quic-events-02: . . . . . . . . . . . . . 66 Since draft-ietf-qlog-quic-events-01: . . . . . . . . . . . . . 67 Since draft-ietf-qlog-quic-events-00: . . . . . . . . . . . . . 67 Since draft-marx-qlog-event-definitions-quic-h3-02: . . . . . . 67 Since draft-marx-qlog-event-definitions-quic-h3-01: . . . . . . 67 Since draft-marx-qlog-event-definitions-quic-h3-00: . . . . . . 68 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 69 1. Introduction This document defines a qlog event schema (Section 8 of [QLOG-MAIN]) containing concrete events for the core QUIC protocol (see [QUIC-TRANSPORT], [QUIC-RECOVERY], and [QUIC-TLS]) and some of its extensions (see [QUIC-DATAGRAM], [GREASEBIT], and [RESET-STREAM-AT]). Marx, et al. Expires 6 May 2027 [Page 4] Internet-Draft QUIC event definitions for qlog November 2026 The event namespace with identifier quic is defined; see Section 2. In this namespace multiple events derive from the qlog abstract Event class (Section 7 of [QLOG-MAIN]), each extending the data field and defining their name field values and semantics. The data types that the events use are defined in Section 8. 1.1. Use of Group IDs QUIC's Original Destination Connection ID (ODCID) can be used as the value of the qlog group_id field. The ODCID is the connection ID that the client chooses for its first Initial packet. It stays the same for the whole connection, unlike the connection IDs that endpoints use, which can change. It can also link packets such as Retry and Version Negotiation to the connection. The ODCID can also be used as the qlog filename or file identifier, optionally suffixed by the vantage point type. For example, abcd1234_server.qlog would contain the server-side trace of the connection with ODCID abcd1234. 1.2. Raw Packet and Frame Information Protected QUIC packets (Initial, 0-RTT, Handshake, and 1-RTT) end with an AEAD authentication tag. Every cipher suite that QUIC version 1 can use has a 16-byte tag; see Section 5.3 of [QUIC-TLS]. When calculating the lengths in RawInfo fields (Section 10 of [QLOG-MAIN]) for these packets, the tag is treated as a 16-byte trailer. 1.3. Events without a Known Connection A qlog trace is typically associated with a single QUIC connection. However, some events cannot be tied to a specific connection, especially on the server. For example, a packet_dropped event (Section 5.7) with the trigger "connection_unknown" is for a packet that matches no known connection. There are various ways to handle these events, each with tradeoffs between file size overhead, flexibility, ease of use, and ease of implementation. Some options include: * Log them in a separate endpoint-wide trace, or use a special group_id value, not associated with a single connection. * Log them in the most recently used trace. * Use additional heuristics to identify the connection, for example the four-tuple in addition to the connection ID. Marx, et al. Expires 6 May 2027 [Page 5] Internet-Draft QUIC event definitions for qlog November 2026 * Buffer events until they can be assigned to a connection, for example events about the Version Negotiation and Retry packets that a server sends before it creates connection state. 1.4. Notational Conventions The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. The event and data structure definitions in this document are expressed in the Concise Data Definition Language [CDDL] and its extensions described in Section 1.2 of [QLOG-MAIN]. This document uses the following from [QLOG-MAIN]: the event namespace and event type concepts; the name, data, tuple, group_id, and time-related fields; and the RawInfo type. Events are defined with an importance level as described in Section 8.3 of [QLOG-MAIN]. As is the case for [QLOG-MAIN], the qlog schema definitions in this document are intentionally agnostic to serialization formats. The choice of format is an implementation decision. 2. Event Schema Definition This document describes how the core QUIC protocol and selected extensions can be expressed in qlog using a newly defined event schema. Per the requirements in Section 8 of [QLOG-MAIN], this document registers the quic namespace. The event schema URI is urn:ietf:params:qlog:events:quic. 2.1. Draft Event Schema Identification This section is to be removed before publishing as an RFC. Only implementations of the final, published RFC can use the events belonging to the event schema with the URI urn:ietf:params:qlog:events:quic. Until such an RFC exists, implementations MUST NOT identify themselves using this URI. Implementations of draft versions of the event schema MUST append the string "-" and the corresponding draft number to the URI. For example, draft 07 of this document is identified using the URI urn:ietf:params:qlog:events:quic-07. Marx, et al. Expires 6 May 2027 [Page 6] Internet-Draft QUIC event definitions for qlog November 2026 The namespace identifier itself is not affected by this requirement. 3. QUIC Event Overview Table 1 summarizes the name value of each event type that is defined in this specification. +======================================+============+==============+ | Name value | Importance | Definition | +======================================+============+==============+ | quic:server_listening | Extra | Section 4.1 | +--------------------------------------+------------+--------------+ | quic:connection_started | Base | Section 4.2 | +--------------------------------------+------------+--------------+ | quic:connection_closed | Base | Section 4.3 | +--------------------------------------+------------+--------------+ | quic:connection_id_updated | Base | Section 4.4 | +--------------------------------------+------------+--------------+ | quic:spin_bit_updated | Base | Section 4.5 | +--------------------------------------+------------+--------------+ | quic:connection_state_updated | Base | Section 4.6 | +--------------------------------------+------------+--------------+ | quic:tuple_assigned | Base | Section 4.7 | +--------------------------------------+------------+--------------+ | quic:mtu_updated | Extra | Section 4.8 | +--------------------------------------+------------+--------------+ | quic:version_information | Core | Section 5.1 | +--------------------------------------+------------+--------------+ | quic:alpn_information | Core | Section 5.2 | +--------------------------------------+------------+--------------+ | quic:parameters_set | Core | Section 5.3 | +--------------------------------------+------------+--------------+ | quic:parameters_restored | Base | Section 5.4 | +--------------------------------------+------------+--------------+ | quic:packet_sent | Core | Section 5.5 | +--------------------------------------+------------+--------------+ | quic:packet_received | Core | Section 5.6 | +--------------------------------------+------------+--------------+ | quic:packet_dropped | Base | Section 5.7 | +--------------------------------------+------------+--------------+ | quic:packet_buffered | Base | Section 5.8 | +--------------------------------------+------------+--------------+ | quic:packets_acked | Extra | Section 5.9 | +--------------------------------------+------------+--------------+ | quic:udp_datagrams_sent | Extra | Section 5.10 | +--------------------------------------+------------+--------------+ | quic:udp_datagrams_received | Extra | Section 5.11 | +--------------------------------------+------------+--------------+ Marx, et al. Expires 6 May 2027 [Page 7] Internet-Draft QUIC event definitions for qlog November 2026 | quic:udp_datagram_dropped | Extra | Section 5.12 | +--------------------------------------+------------+--------------+ | quic:stream_state_updated | Base | Section 5.13 | +--------------------------------------+------------+--------------+ | quic:frames_created | Extra | Section | | | | 5.14.1 | +--------------------------------------+------------+--------------+ | quic:frames_parsed | Extra | Section | | | | 5.14.2 | +--------------------------------------+------------+--------------+ | quic:stream_data_moved | Base | Section 5.15 | +--------------------------------------+------------+--------------+ | quic:datagram_data_moved | Base | Section 5.16 | +--------------------------------------+------------+--------------+ | quic:datagram_dropped | Base | Section 5.17 | +--------------------------------------+------------+--------------+ | quic:connection_data_blocked_updated | Extra | Section 5.18 | +--------------------------------------+------------+--------------+ | quic:stream_data_blocked_updated | Extra | Section 5.19 | +--------------------------------------+------------+--------------+ | quic:datagram_data_blocked_updated | Extra | Section 5.20 | +--------------------------------------+------------+--------------+ | quic:migration_state_updated | Extra | Section 5.21 | +--------------------------------------+------------+--------------+ | quic:timer_updated | Extra | Section 5.22 | +--------------------------------------+------------+--------------+ | quic:key_updated | Base | Section 6.1 | +--------------------------------------+------------+--------------+ | quic:key_discarded | Base | Section 6.2 | +--------------------------------------+------------+--------------+ | quic:recovery_parameters_set | Base | Section 7.1 | +--------------------------------------+------------+--------------+ | quic:recovery_metrics_updated | Core | Section 7.2 | +--------------------------------------+------------+--------------+ | quic:congestion_state_updated | Base | Section 7.3 | +--------------------------------------+------------+--------------+ | quic:packet_lost | Core | Section 7.4 | +--------------------------------------+------------+--------------+ | quic:marked_for_retransmit | Extra | Section 7.5 | +--------------------------------------+------------+--------------+ | quic:ecn_state_updated | Extra | Section 7.6 | +--------------------------------------+------------+--------------+ Table 1: QUIC Events Marx, et al. Expires 6 May 2027 [Page 8] Internet-Draft QUIC event definitions for qlog November 2026 QUIC events extend the $ProtocolEventData extension point defined in Section 8.2 of [QLOG-MAIN]. Additionally, they allow for direct extensibility by their use of per-event extension points via the $$ CDDL "group socket" syntax, as also described in Section 8.2 of [QLOG-MAIN]. QuicEventData = QUICServerListening / QUICConnectionStarted / QUICConnectionClosed / QUICConnectionIDUpdated / QUICSpinBitUpdated / QUICConnectionStateUpdated / QUICTupleAssigned / QUICMTUUpdated / QUICVersionInformation / QUICALPNInformation / QUICParametersSet / QUICParametersRestored / QUICPacketSent / QUICPacketReceived / QUICPacketDropped / QUICPacketBuffered / QUICPacketsAcked / QUICUDPDatagramsSent / QUICUDPDatagramsReceived / QUICUDPDatagramDropped / QUICStreamStateUpdated / QUICFramesCreated / QUICFramesParsed / QUICStreamDataMoved / QUICDatagramDataMoved / QUICDatagramDropped / QUICConnectionDataBlockedUpdated / QUICStreamDataBlockedUpdated / QUICDatagramDataBlockedUpdated / QUICMigrationStateUpdated / QUICTimerUpdated / QUICKeyUpdated / QUICKeyDiscarded / QUICRecoveryParametersSet / QUICRecoveryMetricsUpdated / QUICCongestionStateUpdated / QUICPacketLost / QUICMarkedForRetransmit / QUICECNStateUpdated $ProtocolEventData /= QuicEventData Marx, et al. Expires 6 May 2027 [Page 9] Internet-Draft QUIC event definitions for qlog November 2026 Figure 1: QuicEventData definition and ProtocolEventData extension The concrete QUIC event types are further defined below, their type identifier is the heading name. The subdivisions in sections on Connectivity, Transport, Security, and Recovery are purely for readability. 4. Connectivity Events 4.1. server_listening The server_listening event is emitted when the server starts accepting connections. It has Extra importance level. QUICServerListening = { ? address_v4: IPAddressPort ? address_v6: IPAddressPort ; the server will always answer client Initial packets with a Retry ; packet (no 1-RTT connection setups by choice) ? retry_required: bool * $$quic-serverlistening-extension } Figure 2: QUICServerListening definition Some QUIC stacks do not handle sockets directly, so they cannot log IP addresses or ports. 4.2. connection_started The connection_started event is emitted when a client attempts a new connection, or when a server accepts one. It overlaps with the connection_state_updated event, but it also logs the local and remote endpoint information. It has Base importance level. QUICConnectionStarted = { local: TupleEndpointInfo remote: TupleEndpointInfo * $$quic-connectionstarted-extension } Figure 3: QUICConnectionStarted definition Marx, et al. Expires 6 May 2027 [Page 10] Internet-Draft QUIC event definitions for qlog November 2026 Some QUIC stacks do not handle sockets directly, so they cannot log IP addresses or ports. All fields of TupleEndpointInfo (Figure 45) are optional, so such a stack can log local and remote with only the fields it knows, such as connection_ids. 4.3. connection_closed The connection_closed event is emitted when a connection closes, typically because of an error or a timeout. It has Base importance level. This event overlaps with the connection_state_updated event and the CONNECTION_CLOSE frame. However, when analyzing large deployments, it can be useful to have a single event for each closure, with a reason field for more detail. This event can also log closures due to timeouts or explicit application actions, such as racing several connections and aborting the slowest, which the other events cannot easily capture. The connection_closed event is logged when the local endpoint does one of the following; see Section 10 of [QUIC-TRANSPORT]: * silently discards the connection after an idle timeout; * sends a CONNECTION_CLOSE frame, and enters the closing state; * receives a CONNECTION_CLOSE frame, and enters the draining state; or * receives a Stateless Reset, and enters the draining state. Later changes, such as leaving the closing or draining state, are logged with the connection_state_updated event. QUIC has two kinds of connection error, transport errors and application errors, each with defined codes and semantics; see Section 20 of [QUIC-TRANSPORT]. An implementation can also have internal errors, which it might or might not map to these codes. So this event can carry two levels of error: connection_error or application_error for the QUIC error, and internal_code for a more specific internal error. If an error code has no known string, connection_error or application_error can be "unknown", and error_code then holds the numerical value without variable-length integer encoding. Marx, et al. Expires 6 May 2027 [Page 11] Internet-Draft QUIC event definitions for qlog November 2026 QUICConnectionClosed = { ; which side closed the connection ? initiator: Initiator ? connection_error: $TransportError / CryptoError ? application_error: $ApplicationError ; if connection_error or application_error === "unknown" ? error_code: uint64 ? internal_code: uint64 ? reason: text ? trigger: "idle_timeout" / "application" / "error" / "version_mismatch" / ; when received from peer "stateless_reset" / "aborted" / ; when it is unclear what triggered the CONNECTION_CLOSE "unspecified" * $$quic-connectionclosed-extension } Figure 4: QUICConnectionClosed definition Implementations SHOULD use the most descriptive trigger value that they can determine. This is often clear at the endpoint that closes the connection, but can be less clear at the endpoint that receives the CONNECTION_CLOSE frame. 4.4. connection_id_updated The connection_id_updated event is emitted when either endpoint updates its current connection ID. This typically happens rarely during a connection, so logging this event is more efficient than logging the connection ID in every packet_sent or packet_received event. It has Base importance level. The connection_id_updated event is viewed from the perspective of the endpoint applying the new ID. When the endpoint receives a new connection ID from the peer, the initiator field is "remote". When the endpoint updates its own connection ID, the initiator field is "local". Marx, et al. Expires 6 May 2027 [Page 12] Internet-Draft QUIC event definitions for qlog November 2026 QUICConnectionIDUpdated = { initiator: Initiator ? old: ConnectionID ? new: ConnectionID * $$quic-connectionidupdated-extension } Figure 5: QUICConnectionIDUpdated definition 4.5. spin_bit_updated The spin_bit_updated event is emitted when the value of the QUIC latency spin bit changes; see Section 17.4 of [QUIC-TRANSPORT]. It SHOULD NOT be emitted when the spin bit is set to the value it already has. It has Base importance level. QUICSpinBitUpdated = { state: bool * $$quic-spinbitupdated-extension } Figure 6: QUICSpinBitUpdated definition 4.6. connection_state_updated The connection_state_updated event is emitted when the connection changes state, to track progress through the QUIC handshake and connection close. It has Base importance level. [QUIC-TRANSPORT] does not define a complete set of connection states or their transitions, though it names some, such as the closing and draining states. This document defines the states most likely to be useful for debugging QUIC connections; the list is not exhaustive. QUIC implementations SHOULD log the BaseConnectionStates, and can add the GranularConnectionStates when more in-depth debugging is required. Tools SHOULD handle both kinds equally. QUICConnectionStateUpdated = { ? old: $ConnectionState new: $ConnectionState * $$quic-connectionstateupdated-extension } BaseConnectionStates = Marx, et al. Expires 6 May 2027 [Page 13] Internet-Draft QUIC event definitions for qlog November 2026 ; Initial packet sent/received "attempted" / ; Handshake packet sent/received "handshake_started" / ; Both sent a TLS Finished message ; and verified the peer's TLS Finished message ; 1-RTT packets can be sent ; RFC 9001 Section 4.1.1 "handshake_complete" / ; CONNECTION_CLOSE sent/received, ; stateless reset received or idle timeout "closed" GranularConnectionStates = ; RFC 9000 Section 8.1 ; client sent Handshake packet OR ; client used connection ID chosen by the server OR ; client used valid address validation token "peer_validated" / ; 1-RTT data can be sent by the server, ; but handshake is not done yet ; (server has sent TLS Finished; sometimes called 0.5 RTT data) "early_write" / ; HANDSHAKE_DONE sent/received. ; RFC 9001 Section 4.1.2 "handshake_confirmed" / ; CONNECTION_CLOSE sent "closing" / ; CONNECTION_CLOSE or Stateless Reset received "draining" / ; draining or closing period done, connection state discarded "closed" $ConnectionState /= BaseConnectionStates / GranularConnectionStates Figure 7: QUICConnectionStateUpdated definition The connection_state_updated event overlaps with the connection_closed and connection_started events, and with the frames logged in events such as packet_received. Still, it can be useful to Marx, et al. Expires 6 May 2027 [Page 14] Internet-Draft QUIC event definitions for qlog November 2026 log state transitions separately, especially if they map to an internal state machine. Implementations can therefore use other ConnectionState values that match their internal logic. Tools SHOULD handle these custom states in a similar way to the states defined in this document. 4.7. tuple_assigned The tuple_assigned event associates a TupleID with the details of a network tuple, such as its IP addresses, ports, and connection IDs. It has Base importance level. As described in Section 7.2 of [QLOG-MAIN], each qlog event can be linked to a single network tuple by its top-level tuple field, whose value is a TupleID. Encoding tuple details, such as IP addresses or connection IDs, into the TupleID itself can be cumbersome. This event records them separately, so TupleIDs can stay short, and their details can be updated as the connection evolves. QUICTupleAssigned = { tuple_id: TupleID ; the information for traffic going towards the remote receiver ? tuple_remote: TupleEndpointInfo ; the information for traffic coming in at the local endpoint ? tuple_local: TupleEndpointInfo * $$quic-tupleassigned-extension } Figure 8: QUICTupleAssigned definition Implementations choose their own tuple_id values. For example, a TupleID can be an incrementing integer, the first Destination Connection ID associated with the tuple (or its sequence number), or the two endpoint IP addresses or a hash of them. The empty string ("") is a valid TupleID, and it is the default for events that do not set the tuple field. So the initial tuple of a QUIC connection, on which the handshake occurs (see Section 4.2), is implicitly associated with the TupleID "". Details for this default tuple can be logged with a tuple_assigned event whose tuple_id is "". Marx, et al. Expires 6 May 2027 [Page 15] Internet-Draft QUIC event definitions for qlog November 2026 Because a tuple's details can change during the connection, a TupleID can appear in several tuple_assigned events, and the latest one holds its current details. The first tuple_assigned event for a TupleID indicates that the TupleID was created, and later ones indicate updates. An event with both tuple_local and tuple_remote omitted indicates that the TupleID was abandoned. 4.8. mtu_updated The mtu_updated event indicates that the estimated Path MTU was updated. This happens as part of Path MTU discovery; see Section 14 of [QUIC-TRANSPORT]. It has Extra importance level. QUICMTUUpdated = { ? old: uint32 new: uint32 ; at some point, MTU discovery stops, as a "good enough" ; packet size has been found ? done: bool * $$quic-mtuupdated-extension } Figure 9: QUICMTUUpdated definition The done field defaults to false. 5. Transport Events 5.1. version_information The version_information event supports QUIC version negotiation; see Section 6 of [QUIC-TRANSPORT]. It has Core importance level. Each QUIC endpoint supports one or more versions. The client sends its first Initial packet using one of them. A server that does not support that version can reply with a Version Negotiation packet, which lists the versions the server supports. This event records the versions that each endpoint supports, and the chosen version if there is one. Marx, et al. Expires 6 May 2027 [Page 16] Internet-Draft QUIC event definitions for qlog November 2026 QUICVersionInformation = { ? server_versions: [+ QuicVersion] ? client_versions: [+ QuicVersion] ? chosen_version: QuicVersion * $$quic-versioninformation-extension } Figure 10: QUICVersionInformation definition A client logs this event when it sends its first Initial packet. The event includes client_versions, and chosen_version holds the version used in that packet. If the client then processes a Version Negotiation packet, it logs this event again with client_versions. The event also includes server_versions, which holds the versions from that packet. If the client selects one of them, chosen_version holds it; otherwise, chosen_version is absent. A Version Negotiation packet can also list reserved versions, which an endpoint adds to check that its peer ignores unknown versions; see Section 6.3 of [QUIC-TRANSPORT]. Because server_versions holds the versions from the packet, it can include reserved versions. A server logs this event when it receives a client's first Initial packet. The event includes server_versions. If the server supports the client's version, chosen_version holds the version that the server uses for the connection. Otherwise, chosen_version is absent, and client_versions holds the version the client used. 5.2. alpn_information The alpn_information event supports Application-Layer Protocol Negotiation (ALPN) over the QUIC transport; see [RFC7301] and Section 8.1 of [QUIC-TLS]. It has Core importance level. QUIC endpoints are configured with a list of supported ALPN identifiers. During the TLS handshake, the client sends its list, and the server chooses one identifier from both lists and sends it back. If no match is found, the connection is closed. ALPN identifiers are byte sequences, which are often valid UTF-8. The ALPNIdentifier type can hold either form: byte_value holds the raw bytes, and string_value holds the identifier as text. Implementations SHOULD log at least one form and MAY log both. Marx, et al. Expires 6 May 2027 [Page 17] Internet-Draft QUIC event definitions for qlog November 2026 QUICALPNInformation = { ? server_alpns: [* ALPNIdentifier] ? client_alpns: [* ALPNIdentifier] ? chosen_alpn: ALPNIdentifier * $$quic-alpninformation-extension } ALPNIdentifier = { ? byte_value: hexstring ? string_value: text } Figure 11: QUICALPNInformation definition A client usually logs this event twice: first with client_alpns when it offers its list, then with chosen_alpn when it learns the server's choice. It can instead log a single event with both fields once it learns the choice. A server logs this event once, after it chooses, with client_alpns, server_alpns, and chosen_alpn. 5.3. parameters_set The parameters_set event groups settings from several sources, such as transport parameters and the TLS cipher suite, into a single event. This keeps the number of events low, and lets a reader reason about what the settings do without needing to know which mechanism set each one. It has Core importance level. Most of these settings are set once and never change. However, they are often set at different times during the connection, so a trace can contain several parameters_set events with different fields set. Some settings have two values: one set by the local endpoint, and one requested by the peer. The initiator field says which side the settings in an event come from, so it MUST be correct for every setting in that event. Local and remote settings MUST be logged in separate events. If the local endpoint changes its behavior based on the peer's settings, the outcome can be logged with a new event type, or with fields added through $$quic-parametersset-extension; see Section 8.2 of [QLOG-MAIN]. The initiator field is required. Settings that both endpoints negotiate, such as tls_cipher, are logged in both the local and the remote event. Marx, et al. Expires 6 May 2027 [Page 18] Internet-Draft QUIC event definitions for qlog November 2026 Each setting starts the connection with its default value, or with no value if it has no default. A parameters_set event that includes a setting replaces its previous value; settings that the event omits keep their values. The grease_quic_bit and reset_stream_at settings are true if the transport parameter is present, and default to false. Implementations are not required to recognize, process, or support every parameter that they receive. For example, QUIC implementations ignore transport parameters that they do not support; see Section 7.4.2 of [QUIC-TRANSPORT]. The unknown_parameters field can log the raw values of such parameters, for example reserved (GREASE) parameters, private extensions, or experiments. In the case of connection resumption and 0-RTT, some of the server's parameters are stored up-front at the client and used for the initial connection startup. They are later updated with the server's reply. In these cases, utilize the separate parameters_restored event to indicate the initial values, and this event to indicate the updated values, as normal. QUICParametersSet = { initiator: Initiator ; true if valid session ticket was received ? resumption_allowed: bool ; true if early data extension was enabled on the TLS layer ? early_data_enabled: bool ; e.g., "AES_128_GCM_SHA256" ? tls_cipher: text ; RFC9000 ? original_destination_connection_id: ConnectionID ? initial_source_connection_id: ConnectionID ? retry_source_connection_id: ConnectionID ? stateless_reset_token: StatelessResetToken ? disable_active_migration: bool ? max_idle_timeout: uint64 ? max_udp_payload_size: uint64 ? ack_delay_exponent: uint64 ? max_ack_delay: uint64 ? active_connection_id_limit: uint64 ? initial_max_data: uint64 ? initial_max_stream_data_bidi_local: uint64 ? initial_max_stream_data_bidi_remote: uint64 Marx, et al. Expires 6 May 2027 [Page 19] Internet-Draft QUIC event definitions for qlog November 2026 ? initial_max_stream_data_uni: uint64 ? initial_max_streams_bidi: uint64 ? initial_max_streams_uni: uint64 ? preferred_address: PreferredAddress ? unknown_parameters: [* UnknownParameter] ; RFC9221 ? max_datagram_frame_size: uint64 ; RFC9287 ? grease_quic_bit: bool ; draft-ietf-quic-reliable-stream-reset ? reset_stream_at: bool * $$quic-parametersset-extension } PreferredAddress = { ? address_v4: IPAddressPort ? address_v6: IPAddressPort connection_id: ConnectionID stateless_reset_token: StatelessResetToken } UnknownParameter = { id: uint64 ? value: hexstring } Figure 12: QUICParametersSet definition 5.4. parameters_restored When using QUIC 0-RTT, clients are expected to remember and restore the server's transport parameters from the previous connection. The parameters_restored event is used to indicate which parameters were restored and to which values when utilizing 0-RTT. It has Base importance level. Note that not all transport parameters should be restored (many are even prohibited from being re-utilized). The ones listed here are the ones expected to be useful for correct 0-RTT usage. Marx, et al. Expires 6 May 2027 [Page 20] Internet-Draft QUIC event definitions for qlog November 2026 QUICParametersRestored = { ; RFC9000 ? disable_active_migration: bool ? max_idle_timeout: uint64 ? max_udp_payload_size: uint64 ? active_connection_id_limit: uint64 ? initial_max_data: uint64 ? initial_max_stream_data_bidi_local: uint64 ? initial_max_stream_data_bidi_remote: uint64 ? initial_max_stream_data_uni: uint64 ? initial_max_streams_bidi: uint64 ? initial_max_streams_uni: uint64 ; RFC9221 ? max_datagram_frame_size: uint64 ; RFC9287 ; can only be restored at the client. ; servers MUST NOT restore this parameter! ? grease_quic_bit: bool * $$quic-parametersrestored-extension } Figure 13: QUICParametersRestored definition 5.5. packet_sent The packet_sent event indicates that a QUIC packet was sent. It has Core importance level. Marx, et al. Expires 6 May 2027 [Page 21] Internet-Draft QUIC event definitions for qlog November 2026 QUICPacketSent = { header: PacketHeader ? frames: [* $QuicFrame] ; only if header.packet_type === "stateless_reset" ? stateless_reset_token: StatelessResetToken ; only if header.packet_type === "version_negotiation" ? supported_versions: [+ QuicVersion] ? raw: RawInfo ? datagram_payload_checksum: uint32 ? is_mtu_probe_packet: bool ? trigger: ; RFC 9002 Section 6.1.1 "retransmit_reordered" / ; RFC 9002 Section 6.1.2 "retransmit_timeout" / ; RFC 9002 Section 6.2.4 "pto_probe" / ; RFC 9002 6.2.3 "retransmit_crypto" / ; needed for some CCs to figure out bandwidth allocations ; when there are no normal sends "cc_bandwidth_probe" * $$quic-packetsent-extension } Figure 14: QUICPacketSent definition The encryption level and packet number space are not logged explicitly, because header.packet_type implies them for the packet types that have them. The datagram_payload_checksum field is described in Section 9. The is_mtu_probe_packet field defaults to false. 5.6. packet_received The packet_received event indicates that a QUIC packet was received. It has Core importance level. Marx, et al. Expires 6 May 2027 [Page 22] Internet-Draft QUIC event definitions for qlog November 2026 QUICPacketReceived = { header: PacketHeader ? frames: [* $QuicFrame] ; only if header.packet_type === "stateless_reset" ? stateless_reset_token: StatelessResetToken ; only if header.packet_type === "version_negotiation" ? supported_versions: [+ QuicVersion] ? raw: RawInfo ? datagram_payload_checksum: uint32 ? trigger: ; if packet was buffered because it couldn't be ; decrypted before "keys_available" * $$quic-packetreceived-extension } Figure 15: QUICPacketReceived definition The encryption level and packet number space are not logged explicitly, because header.packet_type implies them for the packet types that have them. The datagram_payload_checksum field is described in Section 9. 5.7. packet_dropped The packet_dropped event indicates that a QUIC packet was dropped. It has Base importance level. Marx, et al. Expires 6 May 2027 [Page 23] Internet-Draft QUIC event definitions for qlog November 2026 QUICPacketDropped = { ; Primarily packet_type should be filled here, ; as other fields might not be decryptable or parsable ? header: PacketHeader ? raw: RawInfo ? datagram_payload_checksum: uint32 ? details: {* text => any} ? trigger: "internal_error" / "rejected" / "unsupported" / "invalid" / "duplicate" / "connection_unknown" / "decryption_failure" / "keys_unavailable" / "general" * $$quic-packetdropped-extension } Figure 16: QUICPacketDropped definition The trigger field gives a general reason for dropping the packet, and the details field can hold additional implementation-specific information. Some example situations for each trigger value include: * "internal_error": not initialized, out of memory * "rejected": limits reached, DDoS protection, unwilling to track more paths * "unsupported": unknown or unsupported version * "invalid": packet parsing or validation error * "duplicate": duplicate packet * "connection_unknown": packet does not relate to a known connection or connection ID * "decryption_failure": decryption failed * "keys_unavailable": decryption keys were unavailable * "general": situations not clearly covered in the other categories Marx, et al. Expires 6 May 2027 [Page 24] Internet-Draft QUIC event definitions for qlog November 2026 Packets dropped as "unsupported" or "connection_unknown" often cannot be tied to a connection; see Section 1.3. The datagram_payload_checksum field is described in Section 9. 5.8. packet_buffered The packet_buffered event is emitted when a packet is buffered because it cannot be processed yet, for example because the keys to decrypt it are not yet available. Its full contents can be logged later, in a packet_received event, once it is processed. It has Base importance level. QUICPacketBuffered = { ; primarily packet_type should be filled here as other elements ; might not be available yet ? header: PacketHeader ? raw: RawInfo ? datagram_payload_checksum: uint32 ? trigger: ; indicates the parser cannot keep up, temporarily buffers ; packet for later processing "backpressure" / ; if packet cannot be decrypted because the proper keys were ; not yet available "keys_unavailable" * $$quic-packetbuffered-extension } Figure 17: QUICPacketBuffered definition The datagram_payload_checksum field is described in Section 9. 5.9. packets_acked The packets_acked event is emitted when one or more sent packets are acknowledged by the peer for the first time. It has Extra importance level. Successive ACK frames can acknowledge the same packet, but this event is emitted only for the first acknowledgment of each packet. This information can also be deduced from received ACK frames, though finding the first acknowledgment needs extra processing. Implementations that do not log frame contents can use this event instead. Marx, et al. Expires 6 May 2027 [Page 25] Internet-Draft QUIC event definitions for qlog November 2026 QUICPacketsAcked = { ? packet_number_space: $PacketNumberSpace ? packet_numbers: [+ uint64] * $$quic-packetsacked-extension } Figure 18: QUICPacketsAcked definition The packet_number_space field defaults to "application_data", the packet number space that most packets in a typical QUIC connection use. 5.10. udp_datagrams_sent The udp_datagrams_sent event indicates that one or more UDP datagrams were passed to the network socket. It can show how QUIC packet buffers are drained to the operating system. It has Extra importance level. QUICUDPDatagramsSent = { ; to support passing multiple at once ? count: uint16 ; The RawInfo fields do not include the UDP headers, ; only the UDP payload ? raw: [+ RawInfo] ; ECN bits in the IP header ? ecn: [+ ECN] ? datagram_payload_checksums: [+ uint32] * $$quic-udpdatagramssent-extension } Figure 19: QUICUDPDatagramsSent definition The RawInfo fields exclude UDP headers, because QUIC implementations do not always handle UDP directly. If an event omits the ecn field, the ECN bits are the same as on the last udp_datagrams_sent event. The datagram_payload_checksums field is described in Section 9. Marx, et al. Expires 6 May 2027 [Page 26] Internet-Draft QUIC event definitions for qlog November 2026 5.11. udp_datagrams_received The udp_datagrams_received event indicates that one or more UDP datagrams were received from the network socket. It can show how the operating system passes datagrams to the user-space stack. It has Extra importance level. QUICUDPDatagramsReceived = { ; to support passing multiple at once ? count: uint16 ; The RawInfo fields do not include the UDP headers, ; only the UDP payload ? raw: [+ RawInfo] ; ECN bits in the IP header ? ecn: [+ ECN] ? datagram_payload_checksums: [+ uint32] * $$quic-udpdatagramsreceived-extension } Figure 20: QUICUDPDatagramsReceived definition If an event omits the ecn field, the ECN bits are the same as on the last udp_datagrams_received event. The datagram_payload_checksums field is described in Section 9. 5.12. udp_datagram_dropped The udp_datagram_dropped event indicates that a UDP datagram was dropped, typically because it does not contain a valid QUIC packet. If the datagram contains a valid QUIC packet that is dropped for another reason, the packet_dropped event (Section 5.7) is used instead. It has Extra importance level. QUICUDPDatagramDropped = { ; The RawInfo fields do not include the UDP headers, ; only the UDP payload ? raw: RawInfo * $$quic-udpdatagramdropped-extension } Marx, et al. Expires 6 May 2027 [Page 27] Internet-Draft QUIC event definitions for qlog November 2026 Figure 21: QUICUDPDatagramDropped definition 5.13. stream_state_updated The stream_state_updated event is emitted when the state of a QUIC stream changes; see Section 3 of [QUIC-TRANSPORT]. Most state changes can be inferred from the frames that are sent and received, but an explicit event can be easier to use. It has Base importance level. QUIC stream IDs encode whether a stream is unidirectional or bidirectional (see Section 2.1 of [QUIC-TRANSPORT]), but the optional stream_type field states it directly. Section 3 of [QUIC-TRANSPORT] describes the sending and receiving parts of a stream, each with its own state machine. The stream_side field says which part's state changed. If both parts change state at the same time, for example when both become "closed", two events with different stream_side values SHOULD be logged. Marx, et al. Expires 6 May 2027 [Page 28] Internet-Draft QUIC event definitions for qlog November 2026 StreamType = "unidirectional" / "bidirectional" QUICStreamStateUpdated = { stream_id: uint64 ? stream_type: StreamType ? old: $StreamState new: $StreamState stream_side: "sending" / "receiving" ? trigger: ; stream state change was initiated by a local action "local" / ; stream state change was initiated by a remote action "remote" * $$quic-streamstateupdated-extension } BaseStreamStates = "idle" / "open" / "closed" GranularStreamStates = ; bidirectional stream states, RFC 9000 Section 3.4. "half_closed_local" / "half_closed_remote" / ; sending-side stream states, RFC 9000 Section 3.1. "ready" / "send" / "data_sent" / "reset_sent" / ; receive-side stream states, RFC 9000 Section 3.2. "receive" / "size_known" / "data_read" / "reset_read" / ; both-side states "data_received" / "reset_received" / ; qlog-defined: memory actually freed "destroyed" $StreamState /= BaseStreamStates / GranularStreamStates Figure 22: QUICStreamStateUpdated definition Marx, et al. Expires 6 May 2027 [Page 29] Internet-Draft QUIC event definitions for qlog November 2026 QUIC implementations SHOULD log the BaseStreamStates, and can add the GranularStreamStates when more in-depth debugging is required. Tools SHOULD handle both kinds equally. The trigger field can show which endpoint initiated a state change, for example when a stream is closed because of a RESET_STREAM or STOP_SENDING frame. 5.14. Frame-Related Events While the packet_sent (Section 5.5) and packet_received (Section 5.6) events can convey all frames contained in a single QUIC packet, some implementations might not be able or willing to include frame information at the moment either event is logged. The frames_created and frames_parsed events log frames independently of packets. A qlog trace can contain both packet- and frame-related events. However, it is RECOMMENDED that implementations avoid generating events with duplicate or redundant frame information, since doing so inflates the size of logs. Where an implementation logs both packet- and frame-related events, the optional packet_numbers field in frame-related events can be used to link frames to packets explicitly. The field is an array so that a single event can log frames that belong to different packets. The frames and packet_numbers arrays are mapped to each other by the position and order of their entries. If the packet_numbers field is logged, every frame MUST have a corresponding packet number at the same index. For example, an instance of the frames_parsed event that represents four STREAM frames received over two packets can be serialized as: "frames":[ {"frame_type":"stream","stream_id":0,"offset":0,"raw":{"length":5}}, {"frame_type":"stream","stream_id":0,"offset":5,"raw":{"length":5}}, {"frame_type":"stream","stream_id":1,"offset":0,"raw":{"length":9}}, {"frame_type":"stream","stream_id":1,"offset":9,"raw":{"length":9}} ], "packet_numbers":[ 1, 1, 2, 2 ] Marx, et al. Expires 6 May 2027 [Page 30] Internet-Draft QUIC event definitions for qlog November 2026 Frame-related events omit information that is available in the packet_received or packet_sent event, such as the packet's encryption level. Use cases that need such information are better served by those events. Extensions can use frame-related events to log information that is not available when a packet event is logged, for example because frame processing was deferred. 5.14.1. frames_created The frames_created event indicates that a set of QUIC frames was created. It has Extra importance level. QUICFramesCreated = { frames: [* $QuicFrame] ? packet_numbers: [* uint64] * $$quic-framescreated-extension } Figure 23: QUICFramesCreated definition 5.14.2. frames_parsed The frames_parsed event indicates that a set of QUIC frames was parsed. It has Extra importance level. QUICFramesParsed = { frames: [* $QuicFrame] ? packet_numbers: [* uint64] * $$quic-framesparsed-extension } Figure 24: QUICFramesParsed definition 5.15. stream_data_moved The stream_data_moved event indicates that QUIC stream data moved between layers. It has Base importance level. For example, data can move from an application protocol such as HTTP/3 to QUIC stream buffers, or the other way. Logging these moves can show the flow of data, how long data stays in each buffer, and the overhead introduced by each layer. Marx, et al. Expires 6 May 2027 [Page 31] Internet-Draft QUIC event definitions for qlog November 2026 This event can also show whether received stream data is passed to the application protocol immediately or in batches. Data can be passed, for example, once per received packet, or in a batch after all received packets are processed. This can help identify bottlenecks, flow control issues, or scheduling problems. The raw.length field gives the number of bytes moved. Because this event covers stream data only, there are no packet or frame headers, and raw.length MUST reflect that. The additional_info field can log information about the stream state. For example, an application that moves data into the transport and ends the stream at the same time can log "fin_set". A transport that has received an instruction to reset a stream can tell the application with "stream_reset". In both cases, raw.length can be omitted or be zero. This event covers only data in QUIC streams. For data in QUIC datagrams, see the datagram_data_moved event (Section 5.16). QUICStreamDataMoved = { ? stream_id: uint64 ? offset: uint64 ? from: $DataLocation ? to: $DataLocation ? additional_info: $DataMovedAdditionalInfo ? raw: RawInfo * $$quic-streamdatamoved-extension } $DataLocation /= "application" / "transport" / "network" $DataMovedAdditionalInfo /= "fin_set" / "stream_reset" Figure 25: QUICStreamDataMoved definition 5.16. datagram_data_moved The datagram_data_moved event indicates that QUIC datagram data (see [QUIC-DATAGRAM]) moved between layers. It has Base importance level. Marx, et al. Expires 6 May 2027 [Page 32] Internet-Draft QUIC event definitions for qlog November 2026 For example, data can move from an application protocol such as WebTransport to QUIC buffers, or the other way. Logging these moves can show the flow of data, how long data stays in each buffer, and the overhead introduced by each layer. This event can also show whether received datagram data is passed to the application protocol immediately or in batches. Data can be passed, for example, once per received packet, or in a batch after all received packets are processed. This can help identify bottlenecks or scheduling problems. The raw.length field gives the number of bytes moved. Because this event covers datagram data only, there are no packet or frame headers, and raw.length MUST reflect that. This event covers only data in QUIC datagrams. For data in QUIC streams, see the stream_data_moved event (Section 5.15). QUICDatagramDataMoved = { ? from: $DataLocation ? to: $DataLocation ? raw: RawInfo * $$quic-datagramdatamoved-extension } Figure 26: QUICDatagramDataMoved definition 5.17. datagram_dropped The datagram_dropped event indicates that QUIC DATAGRAM data (see [RFC9221]) was discarded locally, before sending or after reception. It has Base importance level. The direction field identifies the sending or receiving side, and trigger indicates the reason for discarding the data. The raw.length field MUST count discarded payload bytes, excluding packet and frame headers. Received DATAGRAM data can be discarded while its packet is still acknowledged. For drops of entire QUIC packets, use packet_dropped (Section 5.7). Marx, et al. Expires 6 May 2027 [Page 33] Internet-Draft QUIC event definitions for qlog November 2026 QUICDatagramDropped = { ? direction: "sending" / "receiving" ? raw: RawInfo ? trigger: ; insufficient space in a send or receive buffer "buffer_full" / ; datagram data exceeds the maximum payload size "too_large" / text * $$quic-datagramdropped-extension } Figure 27: QUICDatagramDropped definition 5.18. connection_data_blocked_updated The connection_data_blocked_updated event indicates that the QUIC connection became blocked or unblocked for sending data. It has Extra importance level. Depending on the reason, a blocked connection cannot send stream data, datagram data, or both, until that reason is resolved. The stream_data_blocked_updated and datagram_data_blocked_updated events give more detail for each type of data. QUICConnectionDataBlockedUpdated = { ? old: $BlockedState new: $BlockedState ? reason: $BlockedReason * $$quic-connectiondatablockedupdated-extension } $BlockedState /= "blocked" / "unblocked" $BlockedReason /= "scheduling" / "pacing" / "amplification_protection" / "congestion_control" / "connection_flow_control" / "stream_flow_control" / "stream_id" / "application" Marx, et al. Expires 6 May 2027 [Page 34] Internet-Draft QUIC event definitions for qlog November 2026 Figure 28: QUICConnectionDataBlockedUpdated definition 5.19. stream_data_blocked_updated The stream_data_blocked_updated event indicates that a QUIC stream became blocked or unblocked for sending. It has Extra importance level. QUICStreamDataBlockedUpdated = { ? old: $BlockedState new: $BlockedState stream_id: uint64 ? reason: $BlockedReason * $$quic-streamdatablockedupdated-extension } Figure 29: QUICStreamDataBlockedUpdated definition 5.20. datagram_data_blocked_updated The datagram_data_blocked_updated event indicates that QUIC datagrams became blocked or unblocked for sending. It has Extra importance level. QUICDatagramDataBlockedUpdated = { ? old: $BlockedState new: $BlockedState ? reason: $BlockedReason * $$quic-datagramdatablockedupdated-extension } Figure 30: QUICDatagramDataBlockedUpdated definition 5.21. migration_state_updated The migration_state_updated event logs the progress of a connection migration by a client; see Section 9 of [QUIC-TRANSPORT]. It has Extra importance level. Most details of a migration can be inferred from PATH_CHALLENGE and PATH_RESPONSE frames, together with tuple_assigned events. However, it can be useful to log the progress of the migration, and any decisions made, in a single event. Marx, et al. Expires 6 May 2027 [Page 35] Internet-Draft QUIC event definitions for qlog November 2026 The MigrationState values follow the steps in Section 9 of [QUIC-TRANSPORT]: the probing_* values cover probing a new path (Section 9.1 of [QUIC-TRANSPORT]), and the migration_* values cover migrating the connection (Section 9.2 of [QUIC-TRANSPORT]). Implementations that log per-path information in migration_state_updated events SHOULD also emit tuple_assigned events, to serve as the ground truth for tuple information. QUICMigrationStateUpdated = { ? old: MigrationState new: MigrationState ? tuple_id: TupleID ; the information for traffic going towards the remote receiver ? tuple_remote: TupleEndpointInfo ; the information for traffic coming in at the local endpoint ? tuple_local: TupleEndpointInfo * $$quic-migrationstateupdated-extension } ; Note that MigrationState does not describe a full state machine ; These entries are not necessarily chronological, ; nor will they always all appear during ; a connection migration attempt. MigrationState = ; probing packets are sent, migration not initiated yet "probing_started" / ; did not get reply to probing packets, ; discarding path as an option "probing_abandoned" / ; received reply to probing packets, path is migration candidate "probing_successful" / ; non-probing packets are sent, attempting migration "migration_started" / ; something went wrong during the migration, abandoning attempt "migration_abandoned" / ; new path is now fully used, old path is discarded "migration_complete" Figure 31: QUICMigrationStateUpdated definition Marx, et al. Expires 6 May 2027 [Page 36] Internet-Draft QUIC event definitions for qlog November 2026 5.22. timer_updated The timer_updated event is emitted when a timer changes state. It has Extra importance level. The event_type field takes one of three values: * "set": the timer is set, and delta gives the time until it triggers * "expired": the timer expired * "cancelled": the timer was cancelled An update to an active timer's timeout is logged as a new "set" event. The recovery timer types correspond to timers in Section 6 of [QUIC-RECOVERY] and Appendix A.8 of [QUIC-RECOVERY]: * "ack": the time threshold loss detection timeout * "pto": the probe timeout * "loss_timeout": the single, multi-modal loss detection timer that covers both QUIC uses a variety of timers, and how they are used can depend on the implementation. Implementers can add fields to this event through $$quic-timerupdated-extension, or add timer types through $TimerType. Marx, et al. Expires 6 May 2027 [Page 37] Internet-Draft QUIC event definitions for qlog November 2026 ; a non-exhaustive list of typically employed timers $TimerType /= "ack" / "pto" / "loss_timeout" / "path_validation" / "handshake_timeout" / "idle_timeout" QUICTimerUpdated = { ? timer_type: $TimerType ; to disambiguate in case there are multiple timers ; of the same type ? timer_id: uint64 ; if used for recovery timers, this can be useful information ? packet_number_space: $PacketNumberSpace event_type: "set" / "expired" / "cancelled" ; if event_type === "set": delta time is in ms from ; this event's timestamp until when the timer should trigger ? delta: float32 * $$quic-timerupdated-extension } Figure 32: QUICTimerUpdated definition 6. Security Events 6.1. key_updated The key_updated event indicates that a key was installed or updated. It has Base importance level. This happens when TLS provides new keys during the handshake, and at each 1-RTT key update; see Section 6 of [QUIC-TLS]. Marx, et al. Expires 6 May 2027 [Page 38] Internet-Draft QUIC event definitions for qlog November 2026 QUICKeyUpdated = { key_type: $KeyType ? old: hexstring ? new: hexstring ; needed for 1RTT key updates ? key_phase: uint64 ? trigger: ; (e.g., initial, handshake and 0-RTT keys ; are generated by TLS) "tls" / "remote_update" / "local_update" * $$quic-keyupdated-extension } Figure 33: QUICKeyUpdated definition The key_phase field holds the full key phase, which identifies the generation of keys; it corresponds to @M and @N in Figure 9 of Section 6 of [QUIC-TLS]. The Key Phase bit in the packet header is the least significant bit of this value. 6.2. key_discarded The key_discarded event indicates that a key was discarded. It has Base importance level. Keys are discarded, for example, when the connection moves to a new encryption level during the handshake, or after a key update; see Section 4.9 of [QUIC-TLS]. QUICKeyDiscarded = { key_type: $KeyType ? key: hexstring ; needed for 1RTT key updates ? key_phase: uint64 ? trigger: ; (e.g., initial, handshake and 0-RTT keys ; are generated by TLS) "tls" / "remote_update" / "local_update" * $$quic-keydiscarded-extension } Marx, et al. Expires 6 May 2027 [Page 39] Internet-Draft QUIC event definitions for qlog November 2026 Figure 34: QUICKeyDiscarded definition 7. Recovery Events Most of the events in this section are kept generic to support different recovery approaches and congestion control algorithms. The old, new, and trigger fields of congestion_state_updated, for instance, are free text, so their values depend on the algorithm. Tools that process these events SHOULD try to handle such values even when they don't recognize them. For example, a tool that plots congestion states on a timeline can label an unknown state with the value of the new field. 7.1. recovery_parameters_set The recovery_parameters_set event groups initial parameters from both loss detection and congestion control into a single event. It has Base importance level. These parameters are typically set once and never change. Implementations that change them during the connection MAY emit the recovery_parameters_set event more than once. The reordering_threshold field contains the packet threshold for loss detection, or "disabled" if packet-threshold loss detection is disabled. Marx, et al. Expires 6 May 2027 [Page 40] Internet-Draft QUIC event definitions for qlog November 2026 QUICRecoveryParametersSet = { ; Loss detection, see RFC 9002 Appendix A.2 ; in amount of packets ? reordering_threshold: uint16 / "disabled" ; as RTT multiplier ? time_threshold: float32 ; in ms timer_granularity: uint16 ; in ms ? initial_rtt:float32 ; congestion control, see RFC 9002 Appendix B.2 ; in bytes. Note that this could be updated after pmtud ? max_datagram_size: uint32 ; in bytes ? initial_congestion_window: uint64 ; Note that this could change when max_datagram_size changes ; in bytes ? minimum_congestion_window: uint64 ? loss_reduction_factor: float32 ; as PTO multiplier ? persistent_congestion_threshold: uint16 * $$quic-recoveryparametersset-extension } Figure 35: QUICRecoveryParametersSet definition Parameters that this document does not define, such as those of other loss detection and recovery algorithms, can be added through $$quic- recoveryparametersset-extension. 7.2. recovery_metrics_updated The recovery_metrics_updated event is emitted when one or more of the observable recovery metrics change value. It has Core importance level. Marx, et al. Expires 6 May 2027 [Page 41] Internet-Draft QUIC event definitions for qlog November 2026 Implementations SHOULD group all metric updates that happen at or around the same time into a single recovery_metrics_updated event. For example, if min_rtt and smoothed_rtt change at the same time, they are logged in one event, not two. Each event is only guaranteed to contain at least one of the listed metrics. QUICRecoveryMetricsUpdated = { ; Loss detection, see RFC 9002 Appendix A.3 ; all following rtt fields are expressed in ms ? min_rtt: float32 ? smoothed_rtt: float32 ? latest_rtt: float32 ? rtt_variance: float32 ? pto_count: uint16 ; Congestion control, see RFC 9002 Appendix B.2. ; in bytes ? congestion_window: uint64 ? bytes_in_flight: uint64 ; in bytes ? ssthresh: uint64 ; qlog defined ; sum of all packet number spaces ? packets_in_flight: uint64 ; in bits per second ? pacing_rate: uint64 * $$quic-recoverymetricsupdated-extension } Figure 36: QUICRecoveryMetricsUpdated definition To make logging easier, implementations MAY log values that are the same as previously reported values; for example, two consecutive recovery_metrics_updated events can report the same min_rtt. However, implementations SHOULD try to log only values that changed. Metrics that this document does not define, such as those of other loss detection and recovery algorithms, can be added through $$quic- recoverymetricsupdated-extension. Marx, et al. Expires 6 May 2027 [Page 42] Internet-Draft QUIC event definitions for qlog November 2026 7.3. congestion_state_updated The congestion_state_updated event indicates when the congestion controller enters a new state that changes its behavior. It has Base importance level. This document does not define values for the event's fields. Congestion control algorithms have different states and different causes for moving between them, and stacks can implement the same algorithm differently. For example, the NewReno controller in Section 7.3 of [QUIC-RECOVERY] has three states: slow start, recovery, and congestion avoidance. QUICCongestionStateUpdated = { ? old: text new: text ? trigger: text * $$quic-congestionstateupdated-extension } Figure 37: QUICCongestionStateUpdated definition The trigger field SHOULD be logged if a state change can have more than one cause. For example, NewReno enters recovery when it detects packet loss or when the ECN-CE count increases, so the trigger field shows which of the two caused the change. 7.4. packet_lost The packet_lost event is emitted when loss detection declares a packet lost. It has Core importance level. QUICPacketLost = { ; should include at least the packet_type and packet_number ? header: PacketHeader ? frames: [* $QuicFrame] ? is_mtu_probe_packet: bool ? trigger: "reordering_threshold" / "time_threshold" / "pto_expired" * $$quic-packetlost-extension } Marx, et al. Expires 6 May 2027 [Page 43] Internet-Draft QUIC event definitions for qlog November 2026 Figure 38: QUICPacketLost definition The frames field lists the frames that the lost packet carried. It is optional, because not all implementations keep sent packets in full. The data that is then marked for retransmission can be logged with the marked_for_retransmit event (Section 7.5). The is_mtu_probe_packet field marks a packet that was sent as a Path MTU probe. The loss of such a packet is not a reliable sign of congestion; see Section 14.4 of [QUIC-TRANSPORT]. It defaults to false. The trigger field SHOULD be logged. Its value shows how loss detection declared the packet lost: * reordering_threshold: the packet threshold was exceeded; see Section 6.1.1 of [QUIC-RECOVERY]. * time_threshold: the time threshold was exceeded; see Section 6.1.2 of [QUIC-RECOVERY]. * pto_expired: the probe timeout expired, and the sender declared the packet lost instead of sending a probe; see Section 6.2.4 of [QUIC-RECOVERY]. 7.5. marked_for_retransmit The marked_for_retransmit event indicates which data was marked for retransmission after packet loss was detected. It has Extra importance level. This single event covers all types of retransmittable data, which it logs using the existing QUIC frame definitions. A packet_lost event (Section 7.4) records that a packet was declared lost, and can list the frames it carried. A marked_for_retransmit event records what the implementation then marks for retransmission. The two can differ, because not every frame is retransmitted (ACK and PADDING frames never are), and retransmitted data need not be sent in the same frames; see Section 13.3 of [QUIC-TRANSPORT]. An implementation that retransmits the frames of a lost packet unchanged can log them here, or skip this event and use the frames in the packet_lost event instead. An implementation with more complex logic, such as one that marks ranges of a stream's send buffer as in flight, or one that does not keep sent frames in full, can log frames that describe the data it marked for retransmission. These frames need not match any frame that was sent or will be sent. Marx, et al. Expires 6 May 2027 [Page 44] Internet-Draft QUIC event definitions for qlog November 2026 If an implementation logs packet_sent events, tools can infer much of this data from them. For example, overlapping stream offsets and lengths show when data was retransmitted. QUICMarkedForRetransmit = { frames: [+ $QuicFrame] * $$quic-markedforretransmit-extension } Figure 39: QUICMarkedForRetransmit definition 7.6. ecn_state_updated The ecn_state_updated event indicates a progression in the ECN state machine as described in Appendix A.4 of [QUIC-TRANSPORT]. It has Extra importance level. QUICECNStateUpdated = { ? old: ECNState new: ECNState ? trigger: text * $$quic-ecnstateupdated-extension } ECNState = ; ECN testing in progress "testing" / ; ECN state unknown, waiting for acknowledgements ; for testing packets "unknown" / ; ECN testing failed "failed" / ; testing was successful "capable" Figure 40: QUICECNStateUpdated definition The trigger field can be used to log why the state changed, for example which ECN validation check in Section 13.4.2 of [QUIC-TRANSPORT] failed. 8. QUIC Data Type Definitions 8.1. QuicVersion QuicVersion = hexstring Marx, et al. Expires 6 May 2027 [Page 45] Internet-Draft QUIC event definitions for qlog November 2026 Figure 41: QuicVersion definition 8.2. ConnectionID ConnectionID = hexstring Figure 42: ConnectionID definition 8.3. Initiator Initiator = "local" / "remote" Figure 43: Initiator definition 8.4. IPAddressPort ; an IP address can either be a "human readable" form ; (e.g., "127.0.0.1" for v4 or ; "2001:0db8:85a3:0000:0000:8a2e:0370:7334" for v6) or ; use a raw byte-form (as the string forms can be ambiguous). ; Additionally, the IP address and port pair can be logged as an ; application-defined redacted string for privacy or security reasons. IPAddressPort = { ip: text / hexstring port: uint16 } / text Figure 44: IPAddressPort definition 8.5. TupleEndpointInfo TupleEndpointInfo describes one half, or direction, of a four-tuple. A full tuple has two halves: the server sends to the client's IP address and port, and the client sends to the server's IP address and port. Each direction uses its own destination connection ID. Structures that log tuple information SHOULD therefore include two TupleEndpointInfo instances, one for each half of the tuple. Marx, et al. Expires 6 May 2027 [Page 46] Internet-Draft QUIC event definitions for qlog November 2026 TupleEndpointInfo = { ? address_v4: IPAddressPort ? address_v6: IPAddressPort ; Even though usually only a single ConnectionID ; is associated with a given tuple/path at a time, ; there are situations where there can be an overlap ; or a need to keep track of previous ConnectionIDs ? connection_ids: [+ ConnectionID] * $$quic-tupleendpointinfo-extension } Figure 45: TupleEndpointInfo definition 8.6. PacketType $PacketType /= "initial" / "handshake" / "0RTT" / "1RTT" / "retry" / "version_negotiation" / "stateless_reset" / "unknown" Figure 46: PacketType definition 8.7. PacketNumberSpace $PacketNumberSpace /= "initial" / "handshake" / "application_data" Figure 47: PacketNumberSpace definition 8.8. PacketHeader If a packet type has no known $PacketType string, packet_type can be "unknown", and packet_type_bytes then holds the numerical value without variable-length integer encoding. PacketHeader omits the fixed bit and the reserved bits because QUIC version 1 gives them fixed values; see Section 17 of [QUIC-TRANSPORT]. Their values can be logged in the raw.data field of the event that logs the PacketHeader. Marx, et al. Expires 6 May 2027 [Page 47] Internet-Draft QUIC event definitions for qlog November 2026 QUIC extensions that use these bits, such as the QUIC Bit greasing extension ([GREASEBIT]), can log that use with new events, similar to spin_bit_updated, or with fields added to PacketHeader through $$quic-packetheader-extension. For long header packets of type initial, handshake, and 0RTT, the length field of the packet header is logged in the qlog raw.length field, and the value signifies the length of the packet number plus the payload. PacketHeader = { packet_type: $PacketType ; only if packet_type === "unknown" ? packet_type_bytes: uint64 ; only if packet_type === "1RTT" ? spin_bit: bool ; only if packet_type === "1RTT", and if the key phase was ; determined from the key_phase_bit ? key_phase: uint64 ; only if packet_type === "1RTT", and if key_phase is not set ? key_phase_bit: bool ; only if packet_type === "initial" || "handshake" || "0RTT" || ; "1RTT" ? packet_number_length: uint8 ; only if packet_type === "initial" || "handshake" || "0RTT" || ; "1RTT" ? packet_number: uint64 ; only if packet_type === "initial" || "retry" ? token: Token ; only if present in the header. ; if correctly using connection_id_updated events, ; dcid can be skipped for 1RTT packets ? version: QuicVersion ? scil: uint8 ? dcil: uint8 ? scid: ConnectionID ? dcid: ConnectionID * $$quic-packetheader-extension } Marx, et al. Expires 6 May 2027 [Page 48] Internet-Draft QUIC event definitions for qlog November 2026 Figure 48: PacketHeader definition 8.9. Token Token = { ? type: $TokenType ; decoded fields included in the token ; (typically: peer's IP address, creation time) ? details: { * text => any } ? raw: RawInfo * $$quic-token-extension } $TokenType /= "retry" / "resumption" Figure 49: Token definition The token carried in an Initial packet is either a token from a Retry packet, or one that the server provided earlier in a NEW_TOKEN frame, for address validation in a later connection; see Section 8.1.3 of [QUIC-TRANSPORT]. Both kinds typically encode metadata that the server uses to check the token, but the metadata and its format are implementation-specific. The details field can log that metadata. 8.10. StatelessResetToken ; always 16 bytes StatelessResetToken = hexstring Figure 50: StatelessResetToken definition The stateless reset token is defined in Section 10.3 of [QUIC-TRANSPORT]. 8.11. KeyType Marx, et al. Expires 6 May 2027 [Page 49] Internet-Draft QUIC event definitions for qlog November 2026 $KeyType /= "server_initial_secret" / "client_initial_secret" / "server_handshake_secret" / "client_handshake_secret" / "server_0rtt_secret" / "client_0rtt_secret" / "server_1rtt_secret" / "client_1rtt_secret" Figure 51: KeyType definition 8.12. ECN ECN holds the ECN codepoint carried in the IP header; see Section 13.4 of [QUIC-TRANSPORT]. ECN = "Not-ECT" / "ECT(1)" / "ECT(0)" / "CE" Figure 52: ECN definition 8.13. QUIC Frames The generic $QuicFrame is defined here as a CDDL "type socket" extension point. It can be extended to support additional QUIC frame types. ; The QuicFrame is any key-value map (e.g., JSON object) $QuicFrame /= { * text => any } Figure 53: QuicFrame type socket definition The QUIC frame types defined in this document are as follows: Marx, et al. Expires 6 May 2027 [Page 50] Internet-Draft QUIC event definitions for qlog November 2026 QuicBaseFrames = PaddingFrame / PingFrame / AckFrame / ResetStreamFrame / ResetStreamAtFrame / StopSendingFrame / CryptoFrame / NewTokenFrame / StreamFrame / MaxDataFrame / MaxStreamDataFrame / MaxStreamsFrame / DataBlockedFrame / StreamDataBlockedFrame / StreamsBlockedFrame / NewConnectionIDFrame / RetireConnectionIDFrame / PathChallengeFrame / PathResponseFrame / ConnectionCloseFrame / HandshakeDoneFrame / UnknownFrame / DatagramFrame $QuicFrame /= QuicBaseFrames Figure 54: QuicBaseFrames definition 8.13.1. PaddingFrame A PADDING frame is a single byte with the value 0, so each padding byte is its own frame; see Section 19.1 of [QUIC-TRANSPORT]. Logging each one as a separate PaddingFrame could add hundreds of entries to a single packet event, for example when a client pads an Initial packet to 1200 bytes. Implementations SHOULD instead log a single PaddingFrame for the packet, and set its raw.payload_length field to the number of PADDING frames in the packet. PaddingFrame = { frame_type: "padding" ? raw: RawInfo } Figure 55: PaddingFrame definition 8.13.2. PingFrame Marx, et al. Expires 6 May 2027 [Page 51] Internet-Draft QUIC event definitions for qlog November 2026 PingFrame = { frame_type: "ping" ? raw: RawInfo } Figure 56: PingFrame definition 8.13.3. AckFrame ; either a single number (e.g., [1]) or two numbers (e.g., [1,2]). ; For two numbers: ; the first number is "from": lowest packet number in interval ; the second number is "to": up to and including the highest ; packet number in the interval AckRange = [1*2 uint64] AckFrame = { frame_type: "ack" ; in ms ? ack_delay: float32 ; e.g., looks like [[1,2],[4,5], [7], [10,22]] serialized ? acked_ranges: [+ AckRange] ; ECN (explicit congestion notification) related fields ; (not always present) ? ect1: uint64 ? ect0: uint64 ? ce: uint64 ? raw: RawInfo } Figure 57: AckFrame definition The ranges in acked_ranges do not have to be in order; for example, [[5,9],[1,4]] is valid. The two numbers in a range can be equal; for example, [120,120] means that packet 120 was acknowledged. In that case, implementations SHOULD log [120] instead, and tools MUST handle both forms. 8.13.4. ResetStreamFrame If an error code has no known ApplicationError string, error can be "unknown", and error_code then holds the numerical value without variable-length integer encoding. Marx, et al. Expires 6 May 2027 [Page 52] Internet-Draft QUIC event definitions for qlog November 2026 ResetStreamFrame = { frame_type: "reset_stream" stream_id: uint64 error: $ApplicationError ; if error === "unknown" ? error_code: uint64 ; in bytes final_size: uint64 ? raw: RawInfo } Figure 58: ResetStreamFrame definition 8.13.5. ResetStreamAtFrame The RESET_STREAM_AT frame is defined in Section 4 of [RESET-STREAM-AT]. If an error code has no known ApplicationError string, error can be "unknown", and error_code then holds the numerical value without variable-length integer encoding. ResetStreamAtFrame = { frame_type: "reset_stream_at" stream_id: uint64 error: $ApplicationError ; if error === "unknown" ? error_code: uint64 ; in bytes final_size: uint64 ; in bytes reliable_size: uint64 ? raw: RawInfo } Figure 59: ResetStreamAtFrame definition 8.13.6. StopSendingFrame If an error code has no known ApplicationError string, error can be "unknown", and error_code then holds the numerical value without variable-length integer encoding. Marx, et al. Expires 6 May 2027 [Page 53] Internet-Draft QUIC event definitions for qlog November 2026 StopSendingFrame = { frame_type: "stop_sending" stream_id: uint64 error: $ApplicationError ; if error === "unknown" ? error_code: uint64 ? raw: RawInfo } Figure 60: StopSendingFrame definition 8.13.7. CryptoFrame The length field of the CRYPTO frame MUST be logged in the qlog raw.length field. The other sub-fields of the raw field are optional. CryptoFrame = { frame_type: "crypto" offset: uint64 raw: RawInfo } Figure 61: CryptoFrame definition 8.13.8. NewTokenFrame NewTokenFrame = { frame_type: "new_token" token: Token ? raw: RawInfo } Figure 62: NewTokenFrame definition 8.13.9. StreamFrame If the STREAM frame contains a length field, it MUST be logged in the qlog raw.length field. If it does not, the implementation MAY calculate the actual frame byte length itself and log that in raw.length if necessary. The offset field defaults to 0, and the fin field defaults to false. Marx, et al. Expires 6 May 2027 [Page 54] Internet-Draft QUIC event definitions for qlog November 2026 StreamFrame = { frame_type: "stream" stream_id: uint64 ? offset: uint64 ? fin: bool ? raw: RawInfo } Figure 63: StreamFrame definition 8.13.10. MaxDataFrame MaxDataFrame = { frame_type: "max_data" maximum: uint64 ? raw: RawInfo } Figure 64: MaxDataFrame definition 8.13.11. MaxStreamDataFrame MaxStreamDataFrame = { frame_type: "max_stream_data" stream_id: uint64 maximum: uint64 ? raw: RawInfo } Figure 65: MaxStreamDataFrame definition 8.13.12. MaxStreamsFrame MaxStreamsFrame = { frame_type: "max_streams" stream_type: StreamType maximum: uint64 ? raw: RawInfo } Figure 66: MaxStreamsFrame definition 8.13.13. DataBlockedFrame Marx, et al. Expires 6 May 2027 [Page 55] Internet-Draft QUIC event definitions for qlog November 2026 DataBlockedFrame = { frame_type: "data_blocked" limit: uint64 ? raw: RawInfo } Figure 67: DataBlockedFrame definition 8.13.14. StreamDataBlockedFrame StreamDataBlockedFrame = { frame_type: "stream_data_blocked" stream_id: uint64 limit: uint64 ? raw: RawInfo } Figure 68: StreamDataBlockedFrame definition 8.13.15. StreamsBlockedFrame StreamsBlockedFrame = { frame_type: "streams_blocked" stream_type: StreamType limit: uint64 ? raw: RawInfo } Figure 69: StreamsBlockedFrame definition 8.13.16. NewConnectionIDFrame NewConnectionIDFrame = { frame_type: "new_connection_id" sequence_number: uint64 retire_prior_to: uint64 ; mainly used if e.g., for privacy reasons the full ; connection_id cannot be logged ? connection_id_length: uint8 connection_id: ConnectionID ? stateless_reset_token: StatelessResetToken ? raw: RawInfo } Figure 70: NewConnectionIDFrame definition Marx, et al. Expires 6 May 2027 [Page 56] Internet-Draft QUIC event definitions for qlog November 2026 8.13.17. RetireConnectionIDFrame RetireConnectionIDFrame = { frame_type: "retire_connection_id" sequence_number: uint64 ? raw: RawInfo } Figure 71: RetireConnectionIDFrame definition 8.13.18. PathChallengeFrame PathChallengeFrame = { frame_type: "path_challenge" ; always 8 bytes ? data: hexstring ? raw: RawInfo } Figure 72: PathChallengeFrame definition 8.13.19. PathResponseFrame PathResponseFrame = { frame_type: "path_response" ; always 8 bytes ? data: hexstring ? raw: RawInfo } Figure 73: PathResponseFrame definition 8.13.20. ConnectionCloseFrame If an error code has no known string, error can be "unknown", and error_code then holds the numerical value without variable-length integer encoding. The trigger_frame_type field logs the Frame Type field, which only the transport variant of CONNECTION_CLOSE (type 0x1c) carries; see Section 19.19 of [QUIC-TRANSPORT]. A known frame type is logged as its frame type string, such as "stream". An unknown frame type is logged as the numerical value without variable-length integer encoding. Marx, et al. Expires 6 May 2027 [Page 57] Internet-Draft QUIC event definitions for qlog November 2026 The reason phrase in a CONNECTION_CLOSE frame is a byte sequence, which RFC 9000 recommends be UTF-8; see Section 19.19 of [QUIC-TRANSPORT]. The reason field holds the reason phrase as text, and reason_bytes holds the raw bytes, for example when the value is not UTF-8 or when an endpoint does not want to decode it. Implementations SHOULD log at least one form and MAY log both. ErrorSpace = "transport" / "application" ConnectionCloseFrame = { frame_type: "connection_close" ? error_space: ErrorSpace ? error: $TransportError / CryptoError / $ApplicationError ; if error === "unknown" ? error_code: uint64 ? reason: text ? reason_bytes: hexstring ; when error_space === "transport" ? trigger_frame_type: uint64 / text ? raw: RawInfo } Figure 74: ConnectionCloseFrame definition 8.13.21. HandshakeDoneFrame HandshakeDoneFrame = { frame_type: "handshake_done" ? raw: RawInfo } Figure 75: HandshakeDoneFrame definition 8.13.22. UnknownFrame The frame_type_bytes field holds the numerical value of the frame type without variable-length integer encoding. Marx, et al. Expires 6 May 2027 [Page 58] Internet-Draft QUIC event definitions for qlog November 2026 UnknownFrame = { frame_type: "unknown" frame_type_bytes: uint64 ? raw: RawInfo } Figure 76: UnknownFrame definition 8.13.23. DatagramFrame The QUIC DATAGRAM frame is defined in Section 4 of [QUIC-DATAGRAM]. If the DATAGRAM frame contains a length field, it MUST be logged in the qlog raw.length field. If it does not, the implementation MAY calculate the actual datagram byte length itself and log that in raw.length if necessary. DatagramFrame = { frame_type: "datagram" ? raw: RawInfo } Figure 77: DatagramFrame definition 8.14. TransportError The generic $TransportError is defined here as a CDDL "type socket" extension point. It can be extended to support additional transport errors. Marx, et al. Expires 6 May 2027 [Page 59] Internet-Draft QUIC event definitions for qlog November 2026 $TransportError /= "no_error" / "internal_error" / "connection_refused" / "flow_control_error" / "stream_limit_error" / "stream_state_error" / "final_size_error" / "frame_encoding_error" / "transport_parameter_error" / "connection_id_limit_error" / "protocol_violation" / "invalid_token" / "application_error" / "crypto_buffer_exceeded" / "key_update_error" / "aead_limit_reached" / "no_viable_path" / "unknown" ; there is no value to reflect CRYPTO_ERROR ; use the CryptoError type instead Figure 78: TransportError definition 8.15. ApplicationError Application errors are defined by the application protocol that runs on top of QUIC, such as HTTP/3, so this document cannot list them. $ApplicationError is instead defined as a CDDL "type socket" extension point, with a single "unknown" value. $ApplicationError /= "unknown" Figure 79: ApplicationError definition Event schemas for application protocols MUST add their error strings by extending the $ApplicationError socket; see Section 8.2 of [QLOG-MAIN]. 8.16. CryptoError RFC 9001 converts a TLS alert into a QUIC error code by adding the alert's AlertDescription value to 0x0100; see Section 4.8 of [QUIC-TLS]. Marx, et al. Expires 6 May 2027 [Page 60] Internet-Draft QUIC event definitions for qlog November 2026 A fixed list of strings does not fit this range well, so a CryptoError value is crypto_error_ followed by the resulting QUIC error code in lowercase hexadecimal, from crypto_error_0x100 to crypto_error_0x1ff. For example, a handshake_failure alert, which is 0x0128 in QUIC, is logged as crypto_error_0x128. ; all strings from "crypto_error_0x100" to "crypto_error_0x1ff" CryptoError = text .regexp "crypto_error_0x1[0-9a-f][0-9a-f]" Figure 80: CryptoError definition 9. Handling Packet Coalescing Multiple QUIC packets can be coalesced into a single UDP datagram, especially during the handshake; see Section 12.2 of [QUIC-TRANSPORT]. Neither QUIC nor UDP provides a way to tell which packets shared a datagram. To let tools match QUIC packet events to UDP datagram events, the optional datagram_payload_checksum field carries a 32-bit CRC32c of the UDP payload, calculated as described in Section 11.3 of [RFC9868]. The UDP datagram events carry one checksum per datagram, in their datagram_payload_checksums field. 10. Security and Privacy Considerations The security and privacy considerations discussed in Section 14 of [QLOG-MAIN] apply to this document as well. 11. IANA Considerations This document registers a new entry in the "qlog event schema URIs" registry, which was created in Section 15 of [QLOG-MAIN]: Event schema URI: urn:ietf:params:qlog:events:quic Namespace: quic Event Types: server_listening, connection_started, connection_closed, connection_id_updated, spin_bit_updated, connection_state_updated, tuple_assigned, mtu_updated, version_information, alpn_information, parameters_set, parameters_restored, packet_sent, packet_received, packet_dropped, packet_buffered, packets_acked, udp_datagrams_sent, udp_datagrams_received, udp_datagram_dropped, stream_state_updated, frames_created, frames_parsed, stream_data_moved, datagram_data_moved, datagram_dropped, connection_data_blocked_updated, stream_data_blocked_updated, Marx, et al. Expires 6 May 2027 [Page 61] Internet-Draft QUIC event definitions for qlog November 2026 datagram_data_blocked_updated, migration_state_updated, timer_updated, key_updated, key_discarded, recovery_parameters_set, recovery_metrics_updated, congestion_state_updated, packet_lost, marked_for_retransmit, ecn_state_updated Description: Event definitions related to the QUIC transport protocol. Reference: This document 12. References 12.1. Normative References [CDDL] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, June 2019, . [GREASEBIT] Thomson, M., "Greasing the QUIC Bit", RFC 9287, DOI 10.17487/RFC9287, August 2022, . [QLOG-MAIN] Marx, R., Niccolini, L., Seemann, M., and L. Pardue, "qlog: Structured Logging for Network Protocols", Work in Progress, Internet-Draft, draft-ietf-quic-qlog-main- schema-14, 6 July 2026, . [QUIC-DATAGRAM] Pauly, T., Kinnear, E., and D. Schinazi, "An Unreliable Datagram Extension to QUIC", RFC 9221, DOI 10.17487/RFC9221, March 2022, . [QUIC-RECOVERY] Iyengar, J., Ed. and I. Swett, Ed., "QUIC Loss Detection and Congestion Control", RFC 9002, DOI 10.17487/RFC9002, May 2021, . [QUIC-TLS] Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure QUIC", RFC 9001, DOI 10.17487/RFC9001, May 2021, . Marx, et al. Expires 6 May 2027 [Page 62] Internet-Draft QUIC event definitions for qlog November 2026 [QUIC-TRANSPORT] Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, May 2021, . [RESET-STREAM-AT] Seemann, M. and K. Oku, "QUIC Stream Resets with Partial Delivery", Work in Progress, Internet-Draft, draft-ietf- quic-reliable-stream-reset-11, 6 September 2026, . [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, . [RFC9221] Pauly, T., Kinnear, E., and D. Schinazi, "An Unreliable Datagram Extension to QUIC", RFC 9221, DOI 10.17487/RFC9221, March 2022, . [RFC9868] Touch, J. and C. Heard, Ed., "Transport Options for UDP", RFC 9868, DOI 10.17487/RFC9868, October 2025, . 12.2. Informative References [RFC7301] Friedl, S., Popov, A., Langley, A., and E. Stephan, "Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension", RFC 7301, DOI 10.17487/RFC7301, July 2014, . Acknowledgements Much of the initial work by Robin Marx was done at the Hasselt and KU Leuven Universities. Thanks to Jana Iyengar, Brian Trammell, Dmitri Tikhonov, Stephen Petrides, Jari Arkko, Marcus Ihlar, Victor Vasiliev, Mirja Kuehlewind, Jeremy Laine, Kazu Yamamoto, Christian Huitema, Hugo Landau, Will Hawkins, Mathis Engelbart, Kazuho Oku, and Jonathan Lennox for their feedback and suggestions. Marx, et al. Expires 6 May 2027 [Page 63] Internet-Draft QUIC event definitions for qlog November 2026 Change Log This section is to be removed before publishing as an RFC. Since draft-ietf-qlog-quic-events-13: * Added datagram_dropped (#550) * Wide range of editorial and consistency changes Since draft-ietf-qlog-quic-events-12: * Split frames_processed into 3 events (#513) * Wide range of editorial changes Since draft-ietf-qlog-quic-events-11: * Updated several fields to be uint64 per QUIC spec * Renamed error and error_code fields and logic (#473) * Clarified parameters_set usage (#493) * Replaced all length fields with raw.length (#495) * Change loss_timer_updated to timer_updated (#496) * Renamed path_assigned to tuple_assigned (#491) * Reworked stream_state_updated (#497) * Renamed owner to initiator (#498) * Split up flags in PacketHeader (#478) Since draft-ietf-qlog-quic-events-09: * Several editorial changes * Reworked QUICConnectionStarted to use PathEndpointInfo (#453) * Consistent use of RawInfo and _bytes fields to log raw data (#450) Since draft-ietf-qlog-quic-events-08: * Removed individual categories and put every event in the single quic event schema namespace. Major change (#439) Marx, et al. Expires 6 May 2027 [Page 64] Internet-Draft QUIC event definitions for qlog November 2026 * Renamed recovery:metrics_updated to quic:recovery_metrics_updated and recovery:parameters_set to quic:recovery_parameters_set (#439) * Added unknown_parameters field to parameters_set (#438) * Added extra parameters to parameters_restored (#441) Since draft-ietf-qlog-quic-events-07: * TODO (we forgot...) Since draft-ietf-qlog-quic-events-06: * Added PathAssigned and MigrationStateUpdated events (#336) * Added extension points to parameters_set and parameters_restored (#400) * Removed error_code_value from connection_closed (#386, #392) * Renamed generation to key_phase for key_updated and key_discarded (#390) * Removed retry_token from packet_sent and packet_received (#389) * Updated ALPN handling (#385) * Added key_unavailable trigger to packet_dropped (#381) * Updated several uint32 to uint64 * ProtocolEventBody is now called ProtocolEventData (#352) * Editorial changes (#402, #404, #394, #393) Since draft-ietf-qlog-quic-events-05: * SecurityKeyUpdated: the new key is no longer mandatory to log (#294) * Added ECN related events and metadata (#263) Since draft-ietf-qlog-quic-events-04: * Updated guidance on logging events across connections (#279) * Renamed 'transport' category to 'quic' (#302) Marx, et al. Expires 6 May 2027 [Page 65] Internet-Draft QUIC event definitions for qlog November 2026 * Added support for multiple packet numbers in 'quic:frames_processed' (#307) * Added definitions for RFC9287 (QUIC GREASE Bit extension) (#311) * Added definitions for RFC9221 (QUIC Datagram Frame extension) (#310) * (Temporarily) removed definitions for connection migration events (#317) * Editorial and formatting changes (#298, #299, #304, #306, #327) Since draft-ietf-qlog-quic-events-03: * Ensured consistent use of RawInfo to indicate raw wire bytes (#243) * Renamed UnknownFrame:raw_frame_type to :frame_type_value (#54) * Renamed ConnectionCloseFrame:raw_error_code to :error_code_value (#54) * Changed triggers for packet_dropped (#278) * Added entries to TransportError enum (#285) * Changed minimum_congestion_window to uint64 (#288) Since draft-ietf-qlog-quic-events-02: * Renamed key_retired to key_discarded (#185) * Added fields and events for DPLPMTUD (#135) * Made packet_number optional in PacketHeader (#244) * Removed connection_retried event placeholder (#255) * Changed QuicFrame to a CDDL plug type (#257) * Moved data definitions out of the appendix into separate sections * Added overview Table of Contents Marx, et al. Expires 6 May 2027 [Page 66] Internet-Draft QUIC event definitions for qlog November 2026 Since draft-ietf-qlog-quic-events-01: * Added Stateless Reset Token type (#122) Since draft-ietf-qlog-quic-events-00: * Change the data definition language from TypeScript to CDDL (#143) Since draft-marx-qlog-event-definitions-quic-h3-02: * These changes were done in preparation of the adoption of the drafts by the QUIC working group (#137) * Split QUIC and HTTP/3 events into two separate documents * Moved RawInfo, Importance, Generic events and Simulation events to the main schema document. * Changed to/from value options of the data_moved event Since draft-marx-qlog-event-definitions-quic-h3-01: Major changes: * Moved data_moved from http to transport. Also made the "from" and "to" fields flexible strings instead of an enum (#111,#65) * Moved packet_type fields to PacketHeader. Moved packet_size field out of PacketHeader to RawInfo:length (#40) * Made events that need to log packet_type and packet_number use a header field instead of logging these fields individually * Added support for logging retry, stateless reset and initial tokens (#94,#86,#117) * Moved separate general event categories into a single category "generic" (#47) * Added "transport:connection_closed" event (#43,#85,#78,#49) * Added version_information and alpn_information events (#85,#75,#28) * Added parameters_restored events to help clarify 0-RTT behaviour (#88) Smaller changes: Marx, et al. Expires 6 May 2027 [Page 67] Internet-Draft QUIC event definitions for qlog November 2026 * Merged loss_timer events into one loss_timer_updated event * Field data types are now strongly defined (#10,#39,#36,#115) * Renamed qpack instruction_received and instruction_sent to instruction_created and instruction_parsed (#114) * Updated qpack:dynamic_table_updated.update_type. It now has the value "inserted" instead of "added" (#113) * Updated qpack:dynamic_table_updated. It now has an "owner" field to differentiate encoder vs decoder state (#112) * Removed push_allowed from http:parameters_set (#110) * Removed explicit trigger field indications from events, since this was moved to be a generic property of the "data" field (#80) * Updated transport:connection_id_updated to be more in line with other similar events. Also dropped importance from Core to Base (#45) * Added length property to PaddingFrame (#34) * Added packet_number field to transport:frames_processed (#74) * Added a way to generically log packet header flags (first 8 bits) to PacketHeader * Added additional guidance on which events to log in which situations (#53) * Added "simulation:scenario" event to help indicate simulation details * Added "packets_acked" event (#107) * Added "datagram_ids" to the datagram_X and packet_X events to allow tracking of coalesced QUIC packets (#91) * Extended connection_state_updated with more fine-grained states (#49) Since draft-marx-qlog-event-definitions-quic-h3-00: * Event and category names are now all lowercase * Added many new events and their definitions Marx, et al. Expires 6 May 2027 [Page 68] Internet-Draft QUIC event definitions for qlog November 2026 * "type" fields have been made more specific (especially important for PacketType fields, which are now called packet_type instead of type) * Events are given an importance indicator (issue #22) * Event names are more consistent and use past tense (issue #21) * Triggers have been redefined as properties of the "data" field and updated for most events (issue #23) Authors' Addresses Robin Marx (editor) Akamai Email: rmarx@akamai.com Luca Niccolini (editor) Meta Email: lniccolini@meta.com Marten Seemann (editor) Email: martenseemann@gmail.com Lucas Pardue (editor) Apple Email: lucas@lucaspardue.com Marx, et al. Expires 6 May 2027 [Page 69]