Skip to main content

EventData

Enum EventData 

Source
#[non_exhaustive]
pub enum EventData { ControlMessage { direction: Direction, message_type: u64, message: Value, stream_id: Option<u64>, raw: Option<Vec<u8>>, }, StreamOpened { stream_id: u64, direction: Direction, stream_type: StreamType, track_alias: Option<u64>, subgroup_id: Option<u64>, fetch_request_id: Option<u64>, group_id: Option<u64>, }, StreamClosed { stream_id: u64, error_code: u64, }, ObjectHeader { stream_id: u64, group: u64, object: u64, publisher_priority: u64, object_status: u64, }, ObjectPayload { stream_id: u64, group: u64, object: u64, size: u64, payload: Option<Vec<u8>>, }, StateChange { from: String, to: String, }, Error { error_code: u64, reason: String, stream_id: Option<u64>, kind: Option<ErrorKind>, raw_len: Option<u64>, raw: Option<Vec<u8>>, }, Annotation { label: String, data: Value, }, PeerConnected { endpoint: Option<String>, transport: Option<String>, role: Option<PeerRole>, side: Option<Side>, }, PeerDisconnected { error_code: u64, reason: Option<String>, }, SubscriptionDerivation { upstream: SubscriptionRef, downstream: Vec<SubscriptionRef>, kind: DerivationKind, trace_id: Option<[u8; 16]>, namespace: Option<Vec<Vec<u8>>>, track_name: Option<Vec<u8>>, t_downstream_received: Option<i64>, t_upstream_sent: Option<i64>, t_upstream_ok_received: Option<i64>, t_downstream_ok_sent: Option<i64>, }, Unknown { event_type: u64, fields: Vec<(Value, Value)>, }, }
Expand description

Event-specific payload, discriminated by type.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

ControlMessage

A control-stream message was sent or received (event type 0).

Fields

§direction: Direction

Send or receive.

§message_type: u64

Wire message type ID (e.g. 0x03 for SUBSCRIBE).

§message: Value

Decoded message fields, and not necessarily a map: match on it rather than assuming, or use TraceEvent::request_id.

A recorder MUST write a CBOR map keyed in snake_case here, and an empty map when it decoded nothing. A reader has to take what earlier writers produced, and every capture-* case in the conformance corpus holds a text rendering of the message instead. Such a value is handed back verbatim — unaddressable by key, but not a reason to reject an event the format forbids dropping — and is written back unchanged, because replacing it would destroy the only record of a message nobody will see again.

Unchanged binds what the value says and not how it is encoded. This is a value the reader never looked at, so the two encoding rules reach it on the way out like any other: TraceEvent::extra has the whole of it.

§stream_id: Option<u64>

QUIC stream the message travelled on, when the recorder knows it.

None means unknown, which a reader must not confuse with stream 0. Recorders should fill it in: from draft-17 each request has its own bidirectional stream and responses carry no request ID, so the stream is the only thing pairing a response with its request.

§raw: Option<Vec<u8>>

Raw wire bytes (only at full detail level).

§

StreamOpened

A QUIC stream was opened (event type 1).

The four optional identifiers are what a headers recording has instead of the stream header bytes. No detail level records the bytes of a SUBGROUP_HEADER, a fetch header or a datagram header, so a value carried only there has nothing left to be re-parsed from — and before these fields existed the model could express group, object, priority and status and nothing else, which left a headers trace unable to say which track a stream belonged to.

Each is None when the recorder did not know it — and also when the file carried the key with a value that is not an unsigned integer, in which case the entry is kept verbatim in TraceEvent::extra instead of being read here. A reader must not refuse a stream for lacking one: every recording predating the keys lacks all four.

Fields

§stream_id: u64

QUIC stream ID.

§direction: Direction

Outgoing or incoming.

§stream_type: StreamType

Stream type.

§track_alias: Option<u64>

Track alias the stream carries. Meaningful on any stream type.

§subgroup_id: Option<u64>

Subgroup ID, on a StreamType::Subgroup stream.

§fetch_request_id: Option<u64>

Fetch request ID, on a StreamType::Fetch stream.

A recorder must write it there. It is the only correlation between the stream and the FETCH that asked for it, and unlike a subgroup stream a fetch stream carries no track alias to identify it by instead — so without it a fetch stream in a headers trace names nothing at all.

§group_id: Option<u64>

Group ID, on a StreamType::Datagram stream.

Scoped to datagrams because on a subgroup stream every object carries the group of the stream by construction, so a copy here would be a second field with no independent source. Where it does appear alongside an ObjectHeader for the same stream, the object header is authoritative: this copy serves a reader that has not yet seen an object, and a disagreement between the two is not corruption.

§

StreamClosed

A QUIC stream was closed (event type 2).

Fields

§stream_id: u64

QUIC stream ID.

§error_code: u64

Error code (0 = clean close).

§

ObjectHeader

An object header was parsed from a data stream (event type 3).

Fields

§stream_id: u64

Stream ID this object arrived on.

§group: u64

Group ID.

§object: u64

Object ID.

§publisher_priority: u64

Publisher priority.

§object_status: u64

Object status (0=normal, 1=end-of-group, etc.).

§

ObjectPayload

Object payload bytes were received or sent (event type 4).

Fields

§stream_id: u64

Stream ID.

§group: u64

Group ID.

§object: u64

Object ID.

§size: u64

Payload size in bytes.

§payload: Option<Vec<u8>>

Payload bytes (only at headers+data or full level).

§

StateChange

Session FSM phase transition (event type 5).

Fields

§from: String

Previous session phase.

§to: String

New session phase.

§

Error

Protocol or transport error (event type 6).

The four optional fields are what makes the event evidence rather than an assertion. A peer that sends something malformed is one of the few things a shared trace is uniquely good for — the recording party can see it and the sending party cannot — and until these existed the only field in the format able to hold bytes was a control message’s "raw", so a recorder wanting to keep the offending bytes had to record the violation as a decodable message in order to have somewhere to put them.

Each is None when the recorder did not write it — and also when the file carried the key with a value the field cannot hold, in which case the entry stays verbatim in TraceEvent::extra instead of being read here.

error_observed builds one of these from bytes a recorder has just seen, which is where the cap on raw and the detail levels the two byte-bearing fields sit at are applied.

Fields

§error_code: u64

Error code.

§reason: String

Human-readable reason.

§stream_id: Option<u64>

QUIC stream the error was observed on, when there was one and the recorder knows it.

Optional on the same terms as a control message’s "sid": None means there was no stream or none is known, which a reader must not confuse with stream 0.

§kind: Option<ErrorKind>

What sort of failure this was.

§raw_len: Option<u64>

Byte length of the input the recorder held for this error, before any truncation.

Recorded from headers+sizes upwards, one level below the bytes themselves: how large a malformed message was is often enough on its own to tell a truncated message from a mistyped one, and it carries no content. It is still a size, and this format gates sizes deliberately, so it does not reach a control-level trace.

Where both are present, a value larger than raw’s length is how a reader learns the capture is partial and by how much. Where this is absent, a raw of exactly ERROR_RAW_CAP bytes is the one length the cap makes ambiguous and must be taken as possibly truncated.

§raw: Option<Vec<u8>>

The offending bytes, at full detail only.

Payload-bearing, and gated a level above the event’s own control+: an error naming a data stream has subgroup framing and object payload behind it, so inheriting the event’s level would have put media into traces whose declared level excludes payloads outright.

A recorder caps this at ERROR_RAW_CAP bytes. A reader does not: a longer one read from a file is neither shortened nor refused.

§

Annotation

User-defined annotation (event type 7).

Fields

§label: String

User-defined label.

§data: Value

User-defined data (any CBOR type).

Opaque: nothing here reads it, and it is written back saying what it said. Its encoding is the writer’s, though — see TraceEvent::extra.

§

PeerConnected

A new peer session was established (event type 8).

The identifier for the peer lives on TraceEvent::peer; every later event for that peer repeats it.

Fields

§endpoint: Option<String>

Peer-reported endpoint URI or remote address, best-effort.

§transport: Option<String>

Transport type ("webtransport", "raw-quic", …).

§role: Option<PeerRole>

Role at connection time, if known then.

§side: Option<Side>

Which end of the relay the peer connected from.

§

PeerDisconnected

A peer session ended (event type 9).

Fields

§error_code: u64

Error or close code (0 = clean close).

§reason: Option<String>

Human-readable reason.

§

SubscriptionDerivation

An upstream subscription was created or extended in causal response to downstream ones (event type 10).

This is the primitive multi-hop correlation is built from: a collector reconstructs an end-to-end tree from these links plus the trace IDs propagated along them.

The four timestamps share the timestamp field’s timebase — the emitting source’s own clock. Differences between them are therefore meaningful with no cross-hop clock agreement, which is the point: they measure how long this hop took. Never subtract one source’s timestamp from another’s.

A source emits the event as soon as the downstream SUBSCRIBE arrives, carrying whichever timestamps it has, and may emit it again for the same pair as the rest arrive. A consumer treats the later event as an update to the earlier one, not as a second derivation.

Fields

§upstream: SubscriptionRef

The upstream subscription.

§downstream: Vec<SubscriptionRef>

Every downstream subscription currently served by upstream.

§kind: DerivationKind

Whether the upstream sub was created here or was already running.

§trace_id: Option<[u8; 16]>

Trace ID propagated along the subscription chain, carried as raw bytes at every layer so two implementations produce identical values for the same chain.

§namespace: Option<Vec<Vec<u8>>>

Track namespace the subscription targets, one entry per field.

§track_name: Option<Vec<u8>>

Track name the subscription targets.

§t_downstream_received: Option<i64>

When the downstream SUBSCRIBE was received.

§t_upstream_sent: Option<i64>

When the upstream SUBSCRIBE was transmitted. Absent for terminal subscriptions, where this source is the content origin.

§t_upstream_ok_received: Option<i64>

When SUBSCRIBE_OK was received from upstream. Absent for terminal or still-in-flight subscriptions.

§t_downstream_ok_sent: Option<i64>

When SUBSCRIBE_OK was transmitted downstream. Absent while the subscription is still in flight.

§

Unknown

An event whose type this version of the crate does not know.

New event types may be added without a format version bump, so a reader that rejected them would turn every future addition into a breaking change. The fields are kept verbatim, which means an unknown event survives a read-modify-write round trip intact — intact in what it says, since the encoding written back is this crate’s own. See TraceEvent::extra.

Fields

§event_type: u64

The event type discriminant that was read.

§fields: Vec<(Value, Value)>

Every key and value from the event map other than "n", "t" and "e" — and other than "p", when a peer was read from it. A "p" that is not text is kept here like any other value this crate could not use.

Implementations§

Source§

impl EventData

Source

pub fn error_observed( error_code: u64, reason: impl Into<String>, kind: Option<ErrorKind>, stream_id: Option<u64>, observed: &[u8], detail: &DetailLevel, ) -> Self

An Error built from the bytes a recorder has just observed, for a trace recorded at detail.

This is where the cap on "raw" belongs and the only place this crate applies it: the party constructing an event out of traffic it just saw is the one SPEC.md addresses, and it is the only party that can tell a fresh event from one that arrived by being read. Serializing does not cap, and reading does not refuse — see ERROR_RAW_CAP.

observed is the whole input the recorder held, uncapped. What comes back depends on detail, because the two byte-bearing fields sit at different levels and that is deliberate:

  • raw_len is the full length of observed, from headers+sizes upwards. It is a size, and sizes are gated; it is not gated with the bytes, so it is available in every trace where the bytes must not appear, which is the point of having it.
  • raw is the first ERROR_RAW_CAP bytes of observed, at full only. Below that level nothing is copied.

A level this crate cannot place yields neither.

Where both come back, comparing them is how a reader learns the capture was truncated: raw_len is the length before the cap bit, not after.

Trait Implementations§

Source§

impl Clone for EventData

Source§

fn clone(&self) -> EventData

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EventData

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for EventData

Source§

fn eq(&self, other: &EventData) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for EventData

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.