[][src]Crate qlog

The qlog crate is an implementation of the qlog main schema and qlog QUIC and HTTP/3 events that attempts to closely follow the format of the qlog TypeScript schema. This is just a data model and no support is provided for logging IO, applications can decide themselves the most appropriate method.

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)

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.

Traces

A Trace contains metadata such as the VantagePoint of capture and the Configuration of the Trace.

A very important part of the Trace is the definition of event_fields. A qlog Event is a vector of EventField; this provides great flexibility to log events with any number of EventFields in any order. The event_fields property describes the format of event logging and it is important that events comply with that format. Failing to do so it going to cause problems for qlog analysis tools. For information is available at https://tools.ietf.org/html/draft-marx-qlog-main-schema-01#section-3.3.4

In order to make using qlog a bit easier, this crate expects a qlog Event to consist of the following EventFields in the following order: EventField::RelativeTime, EventField::Category, EventField::Event and EventField::Data. A set of methods are provided to assist in creating a Trace and appending events to it in this format.

Writing out logs

As events occur during the connection, the application appends them to the trace. The qlog crate supports two modes of writing logs: the buffered mode stores everything in memory and requires the application to serialize and write the output, the streaming mode progressively writes serialized JSON output to a writer designated by the application.

Creating a Trace

A typical application needs a single qlog Trace that it appends QUIC and/or HTTP/3 events to:

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".to_string()),
        time_units: Some(qlog::TimeUnits::Ms),
        original_uris: None,
    }),
    None,
);

Adding events

Qlog Events are added to qlog::Trace.events.

It is recommended to use the provided utility methods to append semantically valid events to a trace. However, there is nothing preventing you from creating the events manually.

The following example demonstrates how to log a QUIC packet containing a single Crypto frame. It uses the QuicFrame::crypto(), packet_sent_min() and push_event() methods to create and log a PacketSent event and its EventData.


let scid = [0x7e, 0x37, 0xe4, 0xdc, 0xc6, 0x68, 0x2d, 0xa8];
let dcid = [0x36, 0xce, 0x10, 0x4e, 0xee, 0x50, 0x10, 0x1c];

let pkt_hdr = qlog::PacketHeader::new(
    0,
    Some(1251),
    Some(1224),
    Some(0xff00001b),
    Some(b"7e37e4dcc6682da8"),
    Some(&dcid),
);

let frames =
    vec![qlog::QuicFrame::crypto("0".to_string(), "1000".to_string())];

let event = qlog::event::Event::packet_sent_min(
    qlog::PacketType::Initial,
    pkt_hdr,
    Some(frames),
);

trace.push_event(std::time::Duration::new(0, 0), event);

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:

This example is not tested
{
  "vantage_point": {
    "name": "Example client",
    "type": "client"
  },
  "title": "Example qlog trace",
  "description": "Example qlog trace description",
  "configuration": {
    "time_units": "ms",
    "time_offset": "0"
  },
  "event_fields": [
    "relative_time",
    "category",
    "event",
    "data"
  ],
  "events": [
    [
      "0",
      "transport",
      "packet_sent",
      {
        "packet_type": "initial",
        "header": {
          "packet_number": "0",
          "packet_size": 1251,
          "payload_length": 1224,
          "version": "ff00001b",
          "scil": "8",
          "dcil": "8",
          "scid": "7e37e4dcc6682da8",
          "dcid": "36ce104eee50101c"
        },
        "frames": [
          {
            "frame_type": "crypto",
            "offset": "0",
            "length": "100",
          }
        ]
      }
    ]
  ]
}

Streaming Mode

Create the 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".to_string()),
        time_units: Some(qlog::TimeUnits::Ms),
        original_uris: None,
    }),
    None,
);

Create an object with the Write trait:

let mut file = std::fs::File::create("foo.qlog").unwrap();

Create a QlogStreamer and start serialization to foo.qlog using start_log():

let mut streamer = qlog::QlogStreamer::new(
    qlog::QLOG_VERSION.to_string(),
    Some("Example qlog".to_string()),
    Some("Example qlog description".to_string()),
    None,
    std::time::Instant::now(),
    trace,
    Box::new(file),
);

streamer.start_log().ok();

Adding simple events

Once logging has started you can stream events. Simple events can be written in one step using add_event():

let event = qlog::event::Event::metrics_updated_min();
streamer.add_event(event).ok();

Adding events with frames

Some events contain optional arrays of QUIC frames. If the event has Some(Vec<QuicFrame>), even if it is empty, the streamer enters a frame serializing mode that must be finalized before other events can be logged.

In this example, a PacketSent event is created with an empty frame array and frames are written out later:

let qlog_pkt_hdr = qlog::PacketHeader::with_type(
    qlog::PacketType::OneRtt,
    0,
    Some(1251),
    Some(1224),
    Some(0xff00001b),
    Some(b"7e37e4dcc6682da8"),
    Some(b"36ce104eee50101c"),
);

let event = qlog::event::Event::packet_sent_min(
    qlog::PacketType::OneRtt,
    qlog_pkt_hdr,
    Some(Vec::new()),
);

streamer.add_event(event).ok();

In this example, the frames contained in the QUIC packet are PING and PADDING. Each frame is written using the add_frame() method. Frame writing is concluded with finish_frames().


let ping = qlog::QuicFrame::ping();
let padding = qlog::QuicFrame::padding();

streamer.add_frame(ping, false).ok();
streamer.add_frame(padding, false).ok();

streamer.finish_frames().ok();

Once all events have 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

event

Module-defined Event and functions to work with qlog data structures.

Structs

CommonFields
Configuration
HexSlice
HttpHeader
PacketHeader
PreferredAddress
Qlog
QlogStreamer

A helper object specialized for streaming JSON-serialized qlog to a Write trait.

QpackDynamicTableEntry
QpackHeaderBlockPrefix
Setting
Trace
VantagePoint

Enums

ApplicationError
ApplicationErrorCode
ConnectionErrorCode
ConnectionState
ConnectivityEventType
CryptoError
Error

A quiche qlog error.

ErrorSpace
EventCategory
EventData
EventField
EventType
GenericEventType
H3DataRecipient
H3Owner
H3PushDecision
H3StreamType
Http3EventType
Http3Frame
Http3FrameTypeName
KeyType
PacketType
QPackInstruction
QpackEventType
QpackHeaderBlockRepresentation
QpackHeaderBlockRepresentationTypeName
QpackInstructionTypeName
QpackOwner
QpackStreamState
QpackTableType
QpackUpdateType
QuicFrame
QuicFrameTypeName
RecoveryEventTrigger
RecoveryEventType
SecurityEventTrigger
SecurityEventType
StreamSide
StreamState
StreamType
StreamerState
TimeUnits
TimerType
TransportError
TransportEventTrigger
TransportEventType
TransportOwner
VantagePointType

Constants

QLOG_VERSION

Type Definitions

Result

A specialized Result type for quiche qlog operations.