| Internet-Draft | HTTP/3 qlog event definitions | November 2026 |
| Marx, et al. | Expires 6 May 2027 | [Page] |
This document defines qlog event schemas containing concrete events for the core HTTP/3 protocol and selected extensions. It also defines an http namespace for the Capsule Protocol.¶
Note to RFC editor: Please remove this section before publication.¶
Feedback and discussion are welcome at 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.¶
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.¶
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.¶
This document defines a qlog event schema (Section 8 of [QLOG-MAIN]) containing concrete events for the core HTTP/3 protocol [HTTP/3] and selected extensions: Extended CONNECT ([EXTENDED-CONNECT]), PRIORITY_UPDATE (Section 7 of [PRIORITIZATION]), ORIGIN ([ORIGIN]), and HTTP/3 Datagrams (Section 2.1 of [DGRAM-AND-CAPSULE]). It also defines a schema for the HTTP Capsule Protocol (Section 3 of [DGRAM-AND-CAPSULE]).¶
This document defines two event namespaces: http3 (Section 2) and
http (Section 5). In each 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.¶
Table 1 summarizes the name value of each event type in the http3
namespace. The data types that the events use are defined in Section 4
and Section 7.¶
| Name value | Importance | Definition |
|---|---|---|
| http3:parameters_set | Base | Section 3.1 |
| http3:parameters_restored | Base | Section 3.2 |
| http3:stream_type_set | Base | Section 3.3 |
| http3:priority_updated | Base | Section 3.4 |
| http3:frame_created | Core | Section 3.5 |
| http3:frame_parsed | Core | Section 3.6 |
| http3:datagram_created | Base | Section 3.7 |
| http3:datagram_parsed | Base | Section 3.8 |
| http3:push_resolved | Extra | Section 3.9 |
Table 2 summarizes the name value of each event type in the http
namespace.¶
| Name value | Importance | Definition |
|---|---|---|
| http:capsule_created | Core | Section 6.1 |
| http:capsule_parsed | Core | Section 6.2 |
The events described in this document can be used with or without logging the related QUIC events defined in [QLOG-QUIC]. When they are logged together, the guidance in [QLOG-QUIC] on group IDs, file names, and events without a known connection applies.¶
When they are logged without QUIC events, an implementation can assign a
unique identifier to each HTTP/3 connection and use it as the value of the
qlog group_id field; see Section 7.3 of [QLOG-MAIN]. The identifier 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 identifier abcd1234.¶
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, 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.¶
This document describes how the core HTTP/3 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 http3 namespace. The
event schema URI is urn:ietf:params:qlog:events:http3.¶
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:http3. 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:http3-07.¶
The namespace identifier itself is not affected by this requirement.¶
HTTP/3 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].¶
HTTP3EventData = HTTP3ParametersSet /
HTTP3ParametersRestored /
HTTP3StreamTypeSet /
HTTP3PriorityUpdated /
HTTP3FrameCreated /
HTTP3FrameParsed /
HTTP3DatagramCreated /
HTTP3DatagramParsed /
HTTP3PushResolved
$ProtocolEventData /= HTTP3EventData
HTTP/3 events describe what happens at the HTTP/3 layer, and they don't always
map one-to-one to QUIC events. Data exchanged between the HTTP/3 and QUIC
layers is logged with the stream_data_moved and datagram_data_moved events
in [QLOG-QUIC].¶
HTTP/3 frames are transmitted on QUIC streams, which allows them to span
multiple QUIC packets. Some implementations might send a single large frame,
rather than a sequence of smaller frames, in order to amortize frame header
overhead. HTTP/3 frame headers are represented by the frame_created
(Section 3.5) and frame_parsed (Section 3.6) events.
Subsequent frame payload data transfer is indicated by stream_data_moved
events. Furthermore, stream_data_moved events can appear before
frame_parsed events because implementations need to read data from a stream
in order to parse the frame header.¶
The concrete HTTP/3 event types are further defined below, their type identifier is the heading name.¶
The parameters_set event contains HTTP/3 and QPACK-level settings, mostly
those received from the HTTP/3 SETTINGS frame. It has Base importance level.¶
All these parameters are typically set once and never change. However, they
might be set at different times during the connection, so a trace can contain
multiple instances of parameters_set with different fields set.¶
The initiator field is "local" for settings that this endpoint sent, and
"remote" for settings that it received.
The initiator field is required.¶
HTTP3ParametersSet = {
initiator: Initiator
; RFC9114
? max_field_section_size: uint64
; RFC9204
? max_table_capacity: uint64
? blocked_streams_count: uint64
; RFC9220 (SETTINGS_ENABLE_CONNECT_PROTOCOL)
? extended_connect: uint64
; RFC9297 (SETTINGS_H3_DATAGRAM)
? h3_datagram: uint64
; qlog-specific
; indicates whether this implementation waits for a SETTINGS
; frame before processing requests
? waits_for_settings: bool
; settings that this implementation does not recognize, including
; reserved (GREASE) settings
? unknown_settings: [* HTTP3Setting]
* $$http3-parametersset-extension
}
The unknown_settings field can log settings that the implementation does not
recognize, including reserved settings (Section 7.2.4.1 of [HTTP/3]). Each
entry's name is "unknown" or "reserved", and name_bytes holds the setting
identifier. Settings defined by extensions can instead be added through
$$http3-parametersset-extension.¶
The parameters_restored event indicates which of the server's settings a
client restored from a previous connection to use for 0-RTT, and their values;
see Section 7.2.4.2 of [HTTP/3]. It has Base importance level.¶
When the server's SETTINGS frame arrives, the settings it carries can be logged
with the parameters_set event (Section 3.1).¶
HTTP3ParametersRestored = {
; RFC9114
? max_field_section_size: uint64
; RFC9204
? max_table_capacity: uint64
? blocked_streams_count: uint64
; RFC9220 (SETTINGS_ENABLE_CONNECT_PROTOCOL)
? extended_connect: uint64
; RFC9297 (SETTINGS_H3_DATAGRAM)
? h3_datagram: uint64
* $$http3-parametersrestored-extension
}
The stream_type_set event is emitted when the type of an HTTP/3 stream becomes
known; see Sections 6.1 and 6.2 of [HTTP/3]. It has Base importance level.¶
Client bidirectional streams always have a stream_type value of "request". Server bidirectional streams have no defined use, although extensions could change that.¶
Unidirectional streams in either direction begin with a variable-length
integer type. If the type has no known string, stream_type can be "unknown";
for a reserved type (Section 6.2.3 of [HTTP/3]), it can be "reserved". In
both cases, stream_type_bytes then holds the numerical value without
variable-length integer encoding.¶
The generic $HTTP3StreamType is defined here as a CDDL "type socket" extension
point. It can be extended to support additional HTTP/3 stream types.¶
HTTP3StreamTypeSet = {
? initiator: Initiator
stream_id: uint64
stream_type: $HTTP3StreamType
; only when stream_type === "unknown" or "reserved"
? stream_type_bytes: uint64
; only when stream_type === "push"
? associated_push_id: uint64
* $$http3-streamtypeset-extension
}
$HTTP3StreamType /= "request" /
"control" /
"push" /
"reserved" /
"unknown" /
"qpack_encode" /
"qpack_decode"
The priority_updated event is emitted when the priority of a request stream or
push stream is initialized or updated through mechanisms defined in
[PRIORITIZATION]. It has Base importance level.¶
There can be several reasons why a priority_updated event occurs, and why a
particular value was chosen. For example, the priority can follow signals from
the client or server (see [PRIORITIZATION]), or local policy can change or
override it. The trigger and reason fields can capture these details.¶
HTTP3PriorityUpdated = {
; if the prioritized element is a request stream
? stream_id: uint64
; if the prioritized element is a push stream
? push_id: uint64
? old: HTTP3Priority
new: HTTP3Priority
? trigger: "client_signal_received" /
"local" /
"other"
? reason: "client_signal_only" /
"client_server_merged" /
"local_policy" /
"other"
* $$http3-priorityupdated-extension
}
The frame_created event is emitted when an HTTP/3 frame is created. It has
Core importance level.¶
This event does not necessarily coincide with HTTP/3 data being passed to the
QUIC layer. For that, see the stream_data_moved event in [QLOG-QUIC].¶
HTTP3FrameCreated = {
stream_id: uint64
frame: $HTTP3Frame
* $$http3-framecreated-extension
}
The frame_parsed event is emitted when an HTTP/3 frame is parsed. It has Core
importance level.¶
This event does not necessarily coincide with HTTP/3 data being passed from the
QUIC layer. For that, see the stream_data_moved event in [QLOG-QUIC].¶
HTTP3FrameParsed = {
stream_id: uint64
frame: $HTTP3Frame
* $$http3-frameparsed-extension
}
The datagram_created event is emitted when an HTTP/3 Datagram (Section 2.1 of [DGRAM-AND-CAPSULE]) is created. It has Base importance level.¶
Beyond the Quarter Stream ID field, the remaining contents of HTTP Datagrams are
defined by the protocol that uses them. The datagram_created event can be
extended through the $$http3-datagramcreated-extension socket to log that
information.¶
This event does not necessarily coincide with the HTTP/3 Datagram being passed
to the QUIC layer. For that, see the datagram_data_moved event in
[QLOG-QUIC].¶
HTTP3DatagramCreated = {
quarter_stream_id: uint64
? raw: RawInfo
* $$http3-datagramcreated-extension
}
The datagram_parsed event is emitted when an HTTP/3 Datagram (Section 2.1 of [DGRAM-AND-CAPSULE]) is parsed. It has Base importance level.¶
Beyond the Quarter Stream ID field, the remaining contents of HTTP Datagrams are
defined by the protocol that uses them. The datagram_parsed event can be
extended through the $$http3-datagramparsed-extension socket to log that
information.¶
This event does not necessarily coincide with the HTTP/3 Datagram being passed
from the QUIC layer. For that, see the datagram_data_moved event in
[QLOG-QUIC].¶
HTTP3DatagramParsed = {
quarter_stream_id: uint64
? raw: RawInfo
* $$http3-datagramparsed-extension
}
The push_resolved event is emitted when a resource sent with server push
(Section 4.6 of [HTTP/3]) is claimed (used) or abandoned (rejected) by the
application on top of HTTP/3, such as a web browser. It has Extra importance
level.¶
HTTP3PushResolved = {
? push_id: uint64
; in case this is logged from a place that does not have access
; to the push_id
? stream_id: uint64
decision: HTTP3PushDecision
* $$http3-pushresolved-extension
}
HTTP3PushDecision = "claimed" /
"abandoned"
The following data type definitions can be used in HTTP/3 events.¶
Initiator = "local" /
"remote"
The generic $HTTP3Frame is defined here as a CDDL "type socket" extension point.
It can be extended to support additional HTTP/3 frame types.¶
; The HTTP3Frame is any key-value map (e.g., JSON object)
$HTTP3Frame /= {
* text => any
}
The HTTP/3 frame types defined in this document are as follows:¶
HTTP3BaseFrames = HTTP3DataFrame /
HTTP3HeadersFrame /
HTTP3CancelPushFrame /
HTTP3SettingsFrame /
HTTP3PushPromiseFrame /
HTTP3GoawayFrame /
HTTP3MaxPushIDFrame /
HTTP3ReservedFrame /
HTTP3UnknownFrame
HTTP3ExtensionFrames = HTTP3PriorityUpdateFrame /
HTTP3OriginFrame
$HTTP3Frame /= HTTP3BaseFrames / HTTP3ExtensionFrames
HTTP3DataFrame = {
frame_type: "data"
? raw: RawInfo
}
The payload of an HTTP/3 HEADERS frame is the QPACK-encoding of an HTTP field
section; see Section 7.2.2 of [HTTP/3]. HTTP3HeadersFrame, in contrast,
contains the HTTP field section without QPACK encoding.¶
HTTP3HTTPField = {
? name: text
? name_bytes: hexstring
? value: text
? value_bytes: hexstring
}
HTTP3HeadersFrame = {
frame_type: "headers"
headers: [* HTTP3HTTPField]
? raw: RawInfo
}
For example, the HTTP field section¶
:path: /index.html :method: GET :authority: example.org :scheme: https¶
would be represented in a JSON serialization as:¶
"headers": [
{
"name": ":path",
"value": "/index.html"
},
{
"name": ":method",
"value": "GET"
},
{
"name": ":authority",
"value": "example.org"
},
{
"name": ":scheme",
"value": "https"
}
]
Section 4.2 of [HTTP/3] and Section 5.1 of [HTTP] define rules for the
characters used in HTTP field section names and values. Characters outside the
range are invalid and result in the message being treated as malformed. It can
however be useful to also log these invalid HTTP fields. Characters in the
allowed range can be safely logged by the text type used in the name and
value fields of HTTP3HTTPField. Characters outside the range are unsafe for the
text type and need to be logged using the name_bytes and value_bytes fields.
An instance of HTTP3HTTPField MUST include either the name or name_bytes
field and MAY include both. An HTTP3HTTPField MAY include a value or
value_bytes field or neither.¶
HTTP3CancelPushFrame = {
frame_type: "cancel_push"
push_id: uint64
? raw: RawInfo
}
The settings field can contain zero or more entries. Each setting has a name field, which corresponds to Setting Name as defined (or as would be defined if registered) in the "HTTP/3 Settings" registry maintained at https://www.iana.org/assignments/http3-parameters.¶
If a setting has no known name, name can be "unknown"; for a reserved
setting, it can be "reserved". In both cases, name_bytes then holds the
numerical value without variable-length integer encoding.¶
HTTP3SettingsFrame = {
frame_type: "settings"
settings: [* HTTP3Setting]
? raw: RawInfo
}
HTTP3Setting = {
? name: $HTTP3SettingsName
; only when name === "unknown" or "reserved"
? name_bytes: uint64
value: uint64
}
$HTTP3SettingsName /= "settings_qpack_max_table_capacity" /
"settings_max_field_section_size" /
"settings_qpack_blocked_streams" /
"settings_enable_connect_protocol" /
"settings_h3_datagram" /
"reserved" /
"unknown"
HTTP3PushPromiseFrame = {
frame_type: "push_promise"
push_id: uint64
headers: [* HTTP3HTTPField]
? raw: RawInfo
}
HTTP3GoawayFrame = {
frame_type: "goaway"
; Either stream_id or push_id.
; This is implicit from the sender of the frame
id: uint64
? raw: RawInfo
}
HTTP3MaxPushIDFrame = {
frame_type: "max_push_id"
push_id: uint64
? raw: RawInfo
}
The frame_type_bytes field holds the numerical value of the frame type
without variable-length integer encoding.¶
HTTP3ReservedFrame = {
frame_type: "reserved"
frame_type_bytes: uint64
? raw: RawInfo
}
The frame_type_bytes field holds the numerical value of the frame type
without variable-length integer encoding.¶
HTTP3UnknownFrame = {
frame_type: "unknown"
frame_type_bytes: uint64
? raw: RawInfo
}
The PRIORITY_UPDATE frame is defined in Section 7 of [PRIORITIZATION].¶
HTTP3PriorityUpdateFrame = {
frame_type: "priority_update"
; if the prioritized element is a request stream
? stream_id: uint64
; if the prioritized element is a push stream
? push_id: uint64
priority_field_value: HTTP3Priority
? raw: RawInfo
}
; The priority value in ASCII text, encoded using Structured Fields
; Example: u=5, i
HTTP3Priority = text
The ORIGIN frame is defined in Section 2 of [ORIGIN].¶
HTTP3OriginEntry = {
origin_len: uint16
? ascii_origin: text
}
HTTP3OriginFrame = {
frame_type: "origin"
origin_entries: [* HTTP3OriginEntry]
? raw: RawInfo
}
HTTP3ApplicationError = "http_no_error" /
"http_general_protocol_error" /
"http_internal_error" /
"http_stream_creation_error" /
"http_closed_critical_stream" /
"http_frame_unexpected" /
"http_frame_error" /
"http_excessive_load" /
"http_id_error" /
"http_settings_error" /
"http_missing_settings" /
"http_request_rejected" /
"http_request_cancelled" /
"http_request_incomplete" /
"http_message_error" /
"http_connect_error" /
"http_version_fallback" /
; RFC9204
"qpack_decompression_failed" /
"qpack_encoder_stream_error" /
"qpack_decoder_stream_error" /
; RFC9297
"http_datagram_error"
HTTP3ApplicationError extends the $ApplicationError type socket defined in
[QLOG-QUIC].¶
; ensure HTTP errors are properly validated in QUIC events as well ; e.g., QUIC's ConnectionClose Frame $ApplicationError /= HTTP3ApplicationError¶
This document describes how the Capsule Protocol can be expressed in qlog using
a newly defined event schema. Per the requirements in Section 8 of [QLOG-MAIN], this document registers the http namespace. The event schema URI
is urn:ietf:params:qlog:events:http.¶
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:http. 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:http-07.¶
The namespace identifier itself is not affected by this requirement.¶
HTTP 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].¶
HTTPEventData = HTTPCapsuleCreated /
HTTPCapsuleParsed
$ProtocolEventData /= HTTPEventData
The concrete HTTP event types are further defined below, their type identifier is the heading name.¶
The capsule_created event is emitted when a Capsule is created (see
Section 3 of [DGRAM-AND-CAPSULE]). It has Core importance level.¶
This event does not necessarily coincide with data being passed to the
transport layer. In HTTP/3, capsules are sent inside DATA frames, so the
frame_created event can be logged separately.¶
HTTPCapsuleCreated = {
stream_id: uint64
capsule: $HTTPCapsule
* $$http-capsulecreated-extension
}
The capsule_parsed event is emitted when a Capsule is parsed (see
Section 3 of [DGRAM-AND-CAPSULE]). It has Core importance level.¶
This event does not necessarily coincide with data being passed from the
transport layer. In HTTP/3, capsules are received inside DATA frames, so the
frame_parsed event can be logged separately.¶
HTTPCapsuleParsed = {
stream_id: uint64
capsule: $HTTPCapsule
* $$http-capsuleparsed-extension
}
The following data type definitions can be used in HTTP events.¶
The generic $HTTPCapsule is defined here as a CDDL "type socket" extension
point. It can be extended to support additional capsule types.¶
; The HTTPCapsule is any key-value map (e.g., JSON object)
$HTTPCapsule /= {
* text => any
}
The capsule types defined in this document are as follows:¶
HTTPBaseCapsules = HTTPCapsuleDatagram /
HTTPCapsuleUnknown
$HTTPCapsule /= HTTPBaseCapsules
HTTPCapsuleDatagram = {
capsule_type: "datagram"
? raw: RawInfo
}
The capsule_type_value field holds the numerical value of the capsule type
without variable-length integer encoding.¶
HTTPCapsuleUnknown = {
capsule_type: "unknown"
? capsule_type_value: uint64
? raw: RawInfo
}
The security and privacy considerations discussed in Section 14 of [QLOG-MAIN] apply to this document as well.¶
This document registers two new entries in the "qlog event schema URIs" registry, which was created in Section 15 of [QLOG-MAIN]:¶
urn:ietf:params:qlog:events:http3¶
http3¶
parameters_set, parameters_restored, stream_type_set, priority_updated, frame_created, frame_parsed, datagram_created, datagram_parsed, push_resolved¶
Event definitions related to the HTTP/3 application protocol.¶
This document¶
urn:ietf:params:qlog:events:http¶
http¶
capsule_created, capsule_parsed¶
Event definitions for the Capsule Protocol.¶
This document¶
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, Kazuho Oku, and Jonathan Lennox for their feedback and suggestions.¶
This section is to be removed before publishing as an RFC.¶
Major changes:¶
Smaller changes:¶