Expand description
The qlog crate is an implementation of the qlog main logging schema, QUIC event definitions, and HTTP/3 and QPACK event definitions. The crate provides a qlog data model that can be used for traces with events. It supports serialization and deserialization but defers logging IO choices to applications.
Serialization operates in either a buffered mode or a streaming mode.
The crate uses Serde for conversion between Rust and JSON.
§Overview
qlog is a hierarchical logging format, with a rough structure of:
- Log
- Trace(s)
- Event(s)
- Trace(s)
In practice, a single QUIC connection maps to a single Trace file with one or more Events. Applications can decide whether to combine Traces from different connections into the same Log.
§Buffered Traces with standard JSON
A Trace
is a single JSON object. It contains metadata such as the
VantagePoint
of capture and the Configuration
, and protocol event
data in the Event
array.
JSON Traces allow applications to appends events to them before eventually being serialized as a complete JSON object.
§Creating a Trace
let mut trace = qlog::Trace::new(
qlog::VantagePoint {
name: Some("Example client".to_string()),
ty: qlog::VantagePointType::Client,
flow: None,
},
Some("Example qlog trace".to_string()),
Some("Example qlog trace description".to_string()),
Some(qlog::Configuration {
time_offset: Some(0.0),
original_uris: None,
}),
None,
);
§Adding events to a Trace
Qlog Event
objects are added to qlog::Trace.events
.
The following example demonstrates how to log a qlog QUIC packet_sent
event containing a single Crypto frame. It constructs the necessary elements
of the Event
, then appends it to the trace with push_event()
.
let scid = [0x7e, 0x37, 0xe4, 0xdc, 0xc6, 0x68, 0x2d, 0xa8];
let dcid = [0x36, 0xce, 0x10, 0x4e, 0xee, 0x50, 0x10, 0x1c];
let pkt_hdr = qlog::events::quic::PacketHeader::new(
qlog::events::quic::PacketType::Initial,
Some(0), // packet_number
None, // flags
None, // token
None, // length
Some(0x00000001), // version
Some(&scid),
Some(&dcid),
);
let frames = vec![qlog::events::quic::QuicFrame::Crypto {
offset: 0,
length: 0,
}];
let raw = qlog::events::RawInfo {
length: Some(1251),
payload_length: Some(1224),
data: None,
};
let event_data =
qlog::events::EventData::PacketSent(qlog::events::quic::PacketSent {
header: pkt_hdr,
frames: Some(frames.into()),
is_coalesced: None,
retry_token: None,
stateless_reset_token: None,
supported_versions: None,
raw: Some(raw),
datagram_id: None,
send_at_time: None,
trigger: None,
});
trace.push_event(qlog::events::Event::with_time(0.0, event_data));
§Serializing
The qlog crate has only been tested with serde_json
, however
other serializer targets might work.
For example, serializing the trace created above:
serde_json::to_string_pretty(&trace).unwrap();
which would generate the following:
{
"vantage_point": {
"name": "Example client",
"type": "client"
},
"title": "Example qlog trace",
"description": "Example qlog trace description",
"configuration": {
"time_offset": 0.0
},
"events": [
{
"time": 0.0,
"name": "transport:packet_sent",
"data": {
"header": {
"packet_type": "initial",
"packet_number": 0,
"version": "1",
"scil": 8,
"dcil": 8,
"scid": "7e37e4dcc6682da8",
"dcid": "36ce104eee50101c"
},
"raw": {
"length": 1251,
"payload_length": 1224
},
"frames": [
{
"frame_type": "crypto",
"offset": 0,
"length": 0
}
]
}
}
]
}
§Streaming Traces with JSON-SEQ
To help support streaming serialization of qlogs, draft-ietf-quic-qlog-main-schema-01 introduced support for RFC 7464 JSON Text Sequences (JSON-SEQ). The qlog crate supports this format and provides utilities that aid streaming.
A TraceSeq
contains metadata such as the VantagePoint
of capture and
the Configuration
. However, protocol event data is handled as separate
lines containing a record separator character, a serialized Event
, and a
newline.
§Creating a TraceSeq
let mut trace = qlog::TraceSeq::new(
qlog::VantagePoint {
name: Some("Example client".to_string()),
ty: qlog::VantagePointType::Client,
flow: None,
},
Some("Example qlog trace".to_string()),
Some("Example qlog trace description".to_string()),
Some(qlog::Configuration {
time_offset: Some(0.0),
original_uris: None,
}),
None,
);
Create an object with the Write
trait:
let mut file = std::fs::File::create("foo.sqlog").unwrap();
Create a QlogStreamer
and start serialization to foo.sqlog
using start_log()
:
let mut streamer = qlog::streamer::QlogStreamer::new(
qlog::QLOG_VERSION.to_string(),
Some("Example qlog".to_string()),
Some("Example qlog description".to_string()),
None,
std::time::Instant::now(),
trace,
qlog::events::EventImportance::Base,
Box::new(file),
);
streamer.start_log().ok();
§Adding events
Once logging has started you can stream events. Events
are written in one step using one of add_event()
,
add_event_with_instant()
, add_event_now()
,
add_event_data_with_instant()
, or add_event_data_now()
:
let scid = [0x7e, 0x37, 0xe4, 0xdc, 0xc6, 0x68, 0x2d, 0xa8];
let dcid = [0x36, 0xce, 0x10, 0x4e, 0xee, 0x50, 0x10, 0x1c];
let pkt_hdr = qlog::events::quic::PacketHeader::with_type(
qlog::events::quic::PacketType::OneRtt,
Some(0),
Some(0x00000001),
Some(&scid),
Some(&dcid),
);
let ping = qlog::events::quic::QuicFrame::Ping {
length: None,
payload_length: None,
};
let padding = qlog::events::quic::QuicFrame::Padding {
length: None,
payload_length: 1234,
};
let event_data =
qlog::events::EventData::PacketSent(qlog::events::quic::PacketSent {
header: pkt_hdr,
frames: Some(vec![ping, padding].into()),
is_coalesced: None,
retry_token: None,
stateless_reset_token: None,
supported_versions: None,
raw: None,
datagram_id: None,
send_at_time: None,
trigger: None,
});
let event = qlog::events::Event::with_time(0.0, event_data);
streamer.add_event(event).ok();
Once all events have been written, the log
can be finalized with finish_log()
:
streamer.finish_log().ok();
§Serializing
Serialization to JSON occurs as methods on the QlogStreamer
are called. No additional steps are required.
Modules§
Structs§
Enums§
- A quiche qlog error.
Constants§
Type Aliases§
- A specialized
Result
type for quiche qlog operations.