QUIC event definitions for qlog の紹介

本記事ではIETFで標準化が行われている、QUICなどのロギングを行うフォーマットであるqlogの、QUICに関するイベントを定義している「[QUIC event definitions for qlog](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00)」について紹介します。

# QUIC event definitions for qlog とは
qlogには発生したイベントを記録する`event`という情報をロギングする仕組みがあります。「QUIC event definitions for qlog」では、qlogにQUICの情報をログとして記録するための、イベント定義が行われています。

具体手的には、`event`に対する、イベントの種類を特定するための`name` (`category` + `event`)と定義されたイベントをロギングするときに含む具体的なデータの定義が行われています。

それぞれのイベントには、重要性、`data`に含まれるデータの定義、そして、想定されているイベントを記録するトリガーが説明されています。

なお、qlogの提案自体は2019年ころから行われていましたが、「QUIC event definitions for qlog」まだWG Draftになって間もない状態です。RFC-9000ではなくおそらくQUIC draft-23を参照しています。

そのため今後の議論によって内容が大きく変わる可能性があります。

レポジトリや、Issueの状況は下記から参照可能です。

レポジトリ
https://github.com/quicwg/qlog

議論
https://github.com/quicwg/qlog/issues

# qlog main schemaのおさらい
最初に理解を深めるために、[Main logging schema for qlog](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema-00)を見て、`event`がどのように格納されているのかおさらいをします。

qlogのトップレベルの構成は、以下のようになっています。`traces` の中に、クライアントやサーバーなどで収集したログを格納します。`traces` はクライアントとサーバーのログを単一のファイルに格納可能にするため、配列として定義されています。

```json
   JSON serialization:

   {
       "qlog_version": "draft-03-WIP",
       "qlog_format": "JSON",
       "title": "Name of this particular qlog file (short)",
       "description": "Description for this group of traces (long)",
       "summary": {
           ...
       },
       "traces": [...]
   }
```

`traces` には、クライアントやサーバーなどが個別に収集したログが含まれます。
例として、以下のようなフォーマットで格納されています。

```json
   {
       "title": "Name of this particular trace (short)",
       "description": "Description for this trace (long)",
       "configuration": {
           "time_offset": 150
       },
       "common_fields": {
           "ODCID": "abcde1234",
           "time_format": "absolute"
       },
       "vantage_point": {
           "name": "backend-67",
           "type": "server"
       },
       "events": [...]
   }
```

この中の、`events` という配列に、実際のQUICクライアント・サーバー実行時に起きたイベントをログとして保存します。

`events` には、個別のイベントが含まれます。例として、以下のようなフォーマットで格納されます。

```json
   {
       time: 1553986553572,

       name: "transport:packet_sent",
       data: { ... }

       protocol_type:  ["QUIC","HTTP3"],
       group_id: "127ecc830d98f9d54a42c4f0842aa87e181a",

       time_format: "absolute",

       ODCID: "127ecc830d98f9d54a42c4f0842aa87e181a", // QUIC specific
   }
```

「QUIC event definitions for qlog」では、このイベントに対する`name` フィールドと、`data` フィールドに記録する情報が定義されています。

## `name`について
`name` フィールドは、`data` フィールドに含まれているものを識別するために使用されます。

`name`は、`category`と`type`を結合したものとして扱われます。

`category`と`type`は別々にロギングすることで高レベルでのフィルタリングとイベントタイプの再利用が可能になるようです。ただし、ドラフトではログのサイズが大きく増えるので別々にロギングする方法はあまり使われていないと言及されています。

`name`と、`category`、`type`による記述はそれぞれ以下のようになります。

`name` による記述

```json
   {
       name: "transport:packet_sent"
   }
```

`category`と`type`による記述

```json
   {
       category: "transport",
       type: "packet_sent"
   }
```

なお、`name` を`category` と`type` に分ける方法については著者が[issue](https://github.com/quicwg/qlog/issues/153)を上げているので今後変わるかもしれません。


## QUICに対する`name` の定義
現時点では、`category`は、`connectivity`、`security`、`transport`、`recovery` の4つが定義されています。

現時点のWDでは 「[3.1.  connectivity](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.1)」、「[3.2.  security](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.2)」、「[3.3.  transport](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.3)」、「[3.4.  recovery](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.4)」という構成で、それぞれのカテゴリが定義されています。

そして、「[3.1.1.  server_listening](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.1.1)」のようにカテゴリ毎にイベントタイプが定義されています。

## イベントのImportanceについて
イベントのImportanceはmain schemaの[Event importance indicators](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema-00#section-4.2)で説明されています。

イベントの設計によって、似たような情報や重複がある情報が別々のイベントに含まれるかもしれません。
例えば、QUICの`connection_started`というイベントは、より一般的な`connection_state_updated`と被ります。

このような場合、もし両方のイベントに重複する様な情報が含まれていたとすると、どのイベントを優先するべきかが常に明確とは限りません。（訳注: `connection_stated`と`connection_state_updated`自体はログされるデータ自体は現時点では被っていないように思います。）

そのような場合に判断を助けるために、イベントを定義するときには "Importance Indicator" を定義するべきだと書かれています。


現状では、以下の3つの重要度があります。並び順は重要なものから順番に並んでいます。

- Core
- Base
- Extra

### Core
Coreは、あるプロトコルのログを含む場合はすべてのqlogファイルに含まれるべきイベントです。
典型的には、基本的なパケットやフレームの解析と生成や、基本的な内部状態のメトリクスに紐づいた情報です。

QUICについて、現時点のドラフトでCoreとしているものは、`transport:version_information`、`transport:alpn_information`、`transport:parameters_set`、`transport:packet_received`、`recovery:metric_updated`、`recovery:packet_lost` の7つです。

### Base
"Base"は追加のデバッグのオプションです。
"Base"に含まれるものは多くの場合、"Core"にすべての情報が含まれていれば推測可能ですが、明示的にログを出すことで実装の振る舞いを明確にすることが可能になります。

これらのイベントは、データのバッファへの渡し方、どのように内部の状態が変化したか、実際に受信したデータによってどのような判断が行われたか、などが含まれます。

現状では、14個のイベントが"Base"として定義されています。

実装者が”Core”のイベントをパフォーマンスの問題ですべてロギングしたくないような場合は、代替となるような"Base"のイベントをロギングするべきとドラフトでは書かれています。

### Extra
"Extra"は、プロトコルのデバッグよりは実装の低レベルのデバッグに役立つものとして定義されています。

"Extra"として定義されているものにより細かいレベルでの内部の振る舞いが追跡可能になります。

現状では、8個のイベントが"Extra"として定義されています。

# qlog main schemaとのつながり
このドキュメントでは、main schemaで定義されたフィールド（例えば、`name`, `category`, `type`, `data`, `group_id`, `protocol_type`, 時間に関連するフィールド、importance, `RawInfo`など）が再利用されます。

このドキュメントでQUICのために定義されているイベントを`events`に含める場合、`protocol_type`の配列には"QUIC"を含める必要があります。

もし、`group_id` を使うのであれば、QUICのOriginal Destination Connection ID (ODCID, クライアントが最初に選んだCID) の使用が推奨されています。これは接続全体で変わらないIDとなるからです。

## Raw packet and frame information
main schemaで定義された、`RawInfo` も再利用されます。 `RawInfo`は、低レベルのバイト長とバイトデータ自身を保存するためのデータ構造です。


```ts
class RawInfo {
    length?:uint64; // the full byte length of the entity (e.g., packet or frame) including headers and trailers
    payload_length?:uint64; // the byte length of the entity's payload, without headers or trailers

    data?:bytes; // the contents of the full entity, including headers and trailers
}
```

## Events not belonging to a single connection
特定のQUIC接続に紐づけられないイベントもあります。例えばヘッダに未知のconnection_idがある場合などが考えられます。典型的にはqlogは単一の接続を紐づけるため、それらのイベントをどのようにログするかは明確ではありません。

理想的には特定の接続に紐づけられないエンドポイントレベルのトレースファイルを作り、接続に紐づかないイベントはそこに保存するべきです。しかし、実装によっては現実的でないようです。これらのイベントのほとんどのセマンティクスはプロトコルで十分に定義されており、また、コネクションに属するものとして誤認することは困難であるため、実装者は、たとえ単一のコネクションに強く関連するイベントであっても、特定のコネクションに属さないイベントを他のトレースに記録することを選択してもよいからです。

これによって複数のvantage pointからなるログをマッチさせることが難しくなります。
クライアント側では、version negotiaionやretryを同じトレースに入れるのは簡単ですが、サーバーでは異なるファイルに記録されます。サーバーは、これらのイベントを1つのトレースに入れるために追加の処理が必要になります。

# イベントの定義
繰り返しになりますが、「QUIC event definitions for qlog」では`connectivity`、`security`、`transport`、`recovery`の4つの`category`が定義されています。それぞれの`category` に対して event typeが定義されています。


## Connectivity
`connectivity`には、接続の開始、終了、接続状態の変更などの接続に関するイベントタイプが定義されています。
現状では、検討中のものを含めて7個のイベントタイプが定義されています。

|event type|Importance| サマリー|
|-|-|-|
|server_listening|Extra|サーバーが接続をlistenし始めた時にIPアドレスやポート番号を記録します|
|connection_started|Base|クライアントが新しい接続を開始しようとした時と、サーバーが新しい接続をacceptしたときに使われます|
|onnection_closed|Base|接続が閉じたことを記録します|
|connection_id_updated|Base|サーバーかクライアントのどちらかが接続IDを更新したことを記録します|
|spin_bit_updated|Base|spin bit の更新を記録します|
|connection_retried| 検討中| 検討中|
|connection_state_updated| Base|TLSのハンドシェイクや、接続を閉じるときなどの状態を表します|

マイグレーションに関わるイベントも現在検討中のようです。

### server_listening
Importance: Extra

`server_listening` はサーバーが接続をacceptしたときに記録されます。`server_listening`には、IPアドレスとポート番号を記録できます。

また、サーバーが1-RTT接続を行わない設定の場合に、サーバーが常にretryを送信する設定かを記録する`retry_required?` というフィールドがあるようです。

```ts
   Data:
{
    ip_v4?: IPAddress,
    ip_v6?: IPAddress,
    port_v4?: uint32,
    port_v6?: uint32,

    retry_required?:boolean // the server will always answer client initials with a retry (no 1-RTT connection setups by choice)
}
```

### connection_started
Importance: Base

`connecion_started` は、クライアントが新しい接続を開始しようとした時と、サーバーが新しい接続をacceptした時の両方に使われます。

このイベントは、`connection_state_updated`と被ります。`connection_state_updated`に対して追加でログするべき情報があるので`connection_started`は`connection_state_updated`とは別のイベントとして定義されています。

```ts
   Data:
   {
       ip_version?: "v4" | "v6",
       src_ip?: IPAddress,
       dst_ip?: IPAddress,

       protocol?: string, // transport layer protocol (default "QUIC")
       src_port?: uint32,
       dst_port?: uint32,

       src_cid?: bytes,
       dst_cid?: bytes,
   }
```

### connection_closed
Importance: Base

`coinnection_closed`は、典型的にはエラーやタイムアウトが起きて接続が閉じたことを記録するために使われます。

このイベントは、`connectivity_connection_state_updated` や`CONNECTION_CLOSE`フレームと被ります。しかし、運用的には接続が閉じたことを表すイベントがあったほうが便利なため定義されているようです。

このイベントには上記のイベントと異なり理由を定義するフィールドがあります。例えばタイムアウトが起きて接続を閉じる場合、タイムアウトが起きたということを記録するのがほかのイベントでは難しいためこのイベントが役に立ちます。

このイベントはQUICで定義されている、接続エラーやアプリケーションエラーだけでなく、実装に特有の内部エラーコードにも対応できるようになっています。

```ts
   {
       owner?:"local"|"remote", // which side closed the connection

       connection_code?:TransportError | CryptoError | uint32,
       application_code?:ApplicationError | uint32,
       internal_code?:uint32,

       reason?:string
   }
```

このイベントには、以下のようなトリガーが想定されています。

* clean
* handshake_timeout
* idle_timeout
* error: 規格で、"immediate close" とされている https://datatracker.ietf.org/doc/html/rfc9000#section-10.2
* stateless reset
* version_mismatch
* application: HTTP3のGOAWAYフレームなど


### connection_id_updated
Importance: Base

このイベントは、サーバーかクライアントのどちらかが接続IDを更新したことを記録します。

典型的には接続の中で散発的にしか起こらないので、このイベントタイプを使うことでCIDをすべての`packet_sent`や`packet_received`のイベントに出力するよりも効率的に記録できます。

もし、新しい`connection id`をピアから受け取ったら、dst_ fieldsがセットされます。
もし、自身の`connectin_id` をNEW_CONNECTION_ID によってセットする場合は、src_ fieldsがセットされます。

訳注: 自身が更新した場合は、`owner`を"local"に、ピアが更新した場合は`owner`を"remote"に設定するか、あるいは、`src_cid`、`dst_cid`を設定するかのどちらかになるのではないかと思います。


```ts
   Data:

   {
       owner: "local" | "remote",

       old?:bytes,
       new?:bytes,
   }
```

### spin_bit_updated
Importance: Base

このイベントは、spin bitの値が変わったときだけ記録されます。spin bitの値が変わらないときに記録しようとするとすべての1-RTTパケットを記録することになるため、値が変わったときだけ記録します。

```YD
   Data:

   {
       state: boolean
   }
```

### connection_retried
このイベントはまだ定義されていないようです。


### connection_state_updated
Importance: Base

このイベントは、ハンドシェイクの状態と、接続を閉じるときの状態が記録できます。
それぞれの状態を独立に記録できるように`ConnectionState`という詳細なオプションが提供されています。

一方で、より簡単でシンプルな実装として、`SimpleConnectionState`というものも提供されています。

```ts
Data: 
{
    old?: ConnectionState | SimpleConnectionState,
    new: ConnectionState | SimpleConnectionState
}

enum ConnectionState {
    attempted, // initial sent/received
    peer_validated, // peer address validated by: client sent Handshake packet OR client used CONNID chosen by the server. transport-draft-32, section-8.1
    handshake_started,
    early_write, // 1 RTT can be sent, but handshake isn't done yet
    handshake_complete, // TLS handshake complete: Finished received and sent. tls-draft-32, section-4.1.1
    handshake_confirmed, // HANDSHAKE_DONE sent/received (connection is now "active", 1RTT can be sent). tls-draft-32, section-4.1.2
    closing,
    draining, // connection_close sent/received
    closed // draining period done, connection state discarded
}

enum SimpleConnectionState {
    attempted,
    handshake_started,
    handshake_confirmed,
    closed
}
```

これらの状態は、クライアントとサーバーの以下の状態にマッピングされます。

Client 

|状態名| 状態|
|-|-|
|send inital| attempted|
|get initial| peer_validated|
|get first handshake packet|handskae_statrted|
|get Handshake packet containing Server Finished| handshake_complete|
|send ClientFinished| early_write(1RTT が送信可能）|
|get HANDSHAKE_DONE| handshake_confirmed|


Server

|状態名| 状態|
|-|-|
|get initial| attempted|
|send intial | 検討中　他のフレームと一緒に送信されるから必要ないかもしれない。|
|send handshake EE, Cert, CV|  handshake_started|
|send ServerFinished| early_write (1RTT が送信可能）|
| get first handshake packet / something using a server-issued CID of min length|validated|
|get handshake packet containing ClientFinished|handshake_complete|
|state| handshake_coinfirmed|


attemptedは、概念的には、クライアント観点の`connection started`と同じです。
また、closing or drainingは、`connection closed` イベントと同じです。


### MIGRATION-related events
マイグレーションに関わるイベントはまだ検討中のようです。

## security
`sercurity`には鍵の更新のイベントと鍵のリトライのイベントの二つが現状では定義されています。

|event type|Importance| サマリー|
|-|-|-|
|key_updated|Base|鍵の更新を記録します|
|key_retried|Base|？|

### key_updated
Importance: Base

このイベントは鍵の更新を記録します。`secret_updated`のほうがより正確ですが、現状のドラフトでは、KEY_UPDATEとの一貫性のためこの名前にしているようです。

Key Updateについては、[QUIC-TLSの6. Key Update](https://www.rfc-editor.org/rfc/rfc9001.html#section-6) を参照ください。

```ts
   Data:
   {
       key_type:KeyType,
       old?:bytes,
       new:bytes,
       generation?:uint32 // needed for 1RTT key updates
   }
```

トリガーは以下の項目が考えられています。

*  "tls":  例えば、TLSによるinitial, handshake, 0-RTTのキーの生成が例としてあります。
*  "remote_update" 
*  "local_update"

### key_retired
Importance: Base

現状では説明は特に書かれていませんが、
[Retry Packet](https://www.rfc-editor.org/rfc/rfc9001.html#section-5.8)と関連するのではないかと思います。

```ts
   Data:
   {
       key_type:KeyType,
       key?:bytes,
       generation?:uint32 // needed for 1RTT key updates
   }
```

トリガーは以下の項目が考えられます。

*  "tls" // (e.g., initial, handshake and 0-RTT keys are dropped  implicitly)
*  "remote_update"
*  "local_update"

## transport
`transport`にはQUICのバージョンやALPNの結果、trasnport parameter、パケットの送受信のタイミングやそれにかかわるデータなどの情報が含まれます。

|event type|Importance| サマリー|
|-|-|-|
|version_information|Core|QUICのバージョン情報を記録します   |
|alpn_information|Core|ALPN Negotiationの情報を記録します    |
|parameters_set| Core|transport parameter を記録します |
|parameters_restored|Base|0-RTT接続の場合に、前の接続から復元して使うtransport parameterを記録します|
|packet_sent| Core|送信するQUICパケットの情報を記録します |
|packet_received| Core|受信したQUICパケットの情報を記録します |
|packet_dropped| Base|QUICパケットが、解析に失敗などしてドロップした場合に使われます|
| packet_buffered| Base|パケットがバッファリングされて処理されていないときに使います|
|packets_acked | Extra|QUICパケットがAckされた場合に使用します |
|datagrams_sent| Extra|UDPのデータグラムをソケットにパスしたときにログに書き込みます（DATAGRAM拡張ではありません） |
|datagrams_received| Extra|UDPのデータグラムをOS側から受信したときに使います |
|datagram_dropped| Extra|UDPのデータグラムがドロップしたときに使われます|
|stream_state_updated| Base|ストリームの状態が更新されたときに発行されます  |
| frames_processed| Extra|QUICのフレームが処理されたことを表すときに使われます|
| data_moved| Base|データが異なるレイヤを移動したことを記録するときに使われます |




### version_information
Importance: Core

QUICのエンドポイントはサーバー・クライアントともにサポートしているQUICのversionを保持しています。クライアントは最もそれらしいバージョンを最初のinitialに使います。

サーバーはそのバージョンをサポートしていない場合、サーバーがサポートしているバージョンが含まれているversion_negotiation パケットを送信します。

クライアントはその中からバージョンを選択します。

このイベントはそれらの情報を一つのイベントにまとめます。このイベントは、エンドポイントがサポートしているバージョンを、バージョンネゴシエーションが実際に行われたタイミングじゃなくてもログに記録することができます。

参考: [6. Version Negotiation](https://datatracker.ietf.org/doc/html/rfc9000#section-6)、[15. Versions](https://datatracker.ietf.org/doc/html/rfc9000#section-15)


```ts
   Data:
   {
       server_versions?:Array<bytes>,
       client_versions?:Array<bytes>,
       chosen_version?:bytes
   }
```

このイベントは以下のような使い方が想定されています。

- クライアントがinitialを送ったときに、`client_version`と`chosen_version` をセットしてログを記録します。
- サーバーがクライアントからのサポートしているバージョンを含むinitialを受け取ったら、このイベントにを`server_version`と`chosen_version`をセットしてログを書き込みます。
- サーバーがサポートしていないバージョンをクライアントから受け取ったら、`sever_version`にサーバーがサポートしているバージョンを、`client_version`にクライアントが使おうとしたバージョンをログに記録します。`chosen_version`を空にすることで、クライアントとサーバーのバージョンにマッチするものがなかったことを現わせます。
- クライアントは、version negotiation packetをサーバーから受け取ったら、`client_version`の集合と、 `server_versions`の集合と`chosen_version`（次のinitial packetで使う）をログに書き込みます。

### alpn_information
Importance: Core

QUICの実装はそれぞれアプリケーションレベルの実装の一覧とサポートしているバージョンを持っています。

TLSのAPLN拡張として、クライアントは自身がサポートしている一覧をinitialに入れて送ります。

もし共通のものがあればサーバーは最適なものを選んでクライアントに返します。

共通のものがない場合はコネクションを閉じます。

```ts
   Data:
   {
       server_alpns?:Array<string>,
       client_alpns?:Array<string>,
       chosen_alpn?:string
   }
```

以下のような使い方が想定されています。

* initialを送るときにクライアントは`client_alpns`の集合をログに記録する。
* サーバーはサポートしているalpnを受信した時に、サーバーのalpn、クライアントのalpn、選んでクライアントに送ったalpnをサーバーのログに含めます。
* クライアントは、alpnをinitialで受信したら`chosen_alpn`をログに記録します。
* クライアントは最初のイベントをログせずに、サーバーからintialを受信したときに`client_alpn`と`chosen_alpn`を一緒に保存することもできます。

### parameters_set
Importance: Core

`parameters_set`は、transport parameter、 TLC ciphersなどいくつかの異なる情報を一つのイベントとして定義します。このように定義しているのは、イベントの量を最小限に抑え、概念的な設定の影響をその基礎となるメカニズムから切り離すことで、高レベルの推論を容易にするためです。

典型的にはこれらの設定は一度設定されたら変更されません。しかし、典型的には接続の異なるタイミングで使用されます。そのため、`parameter_set`のイベントは異なるフィールドを持ったインスタンスが存在することになります。

設定には、ローカルでセットしたものとリモートのピアからリクエストされたものの2種類が存在します。これは"owner"フィールドに反映されます。そのため、このフィールドは、1つのイベントインスタンスに含まれるすべての設定に対して正しくなければなりません。 2つの側からの設定を記録する必要がある場合は   2つの別々のイベントインスタンスを発行しなければなりません。

接続の再開と0-RTTの場合、サーバーのいくつかのパラメータはクライアントに保存され、接続の開始時に使用されます。
それらは後程サーバーからのリプライによって更新されます。この場合、"parameters_restored"を活用し初期値と、更新された値を表すことになります。

```ts
Data:
{
    owner?:"local" | "remote",

    resumption_allowed?:boolean, // valid session ticket was received
    early_data_enabled?:boolean, // early data extension was enabled on the TLS layer
    tls_cipher?:string, // (e.g., "AES_128_GCM_SHA256")
    aead_tag_length?:uint8, // depends on the TLS cipher, but it's easier to be explicit. Default value is 16

    // transport parameters from the TLS layer:
    original_destination_connection_id?:bytes,
    initial_source_connection_id?:bytes,
    retry_source_connection_id?:bytes,
    stateless_reset_token?:Token,
    disable_active_migration?:boolean,

    max_idle_timeout?:uint64,
    max_udp_payload_size?:uint32,
    ack_delay_exponent?:uint16,
    max_ack_delay?:uint16,
    active_connection_id_limit?:uint32,

    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,

    preferred_address?:PreferredAddress
}

interface PreferredAddress {
    ip_v4:IPAddress,
    ip_v6:IPAddress,

    port_v4:uint16,
    port_v6:uint16,

    connection_id:bytes,
    stateless_reset_token:Token
}
```

このイベントは、unknown (greased)なトランスポートパラメータや、独自仕様のトランスポートパラメータを含むことが可能です。

### parameters_restored
Importance: Base

0-RTTを使う時、クライアントは以前の接続のサーバーのトランスポートパラメータを記憶して保存していることが想定されます。このイベントは、どのパラメータが復元されたのかを記録できます。

再利用が禁止されているものもあるため、すべてのトランスポートパラメータ―が復元されるべきではありません。ここに定義されているものは0-RTTを正しく使うために役立つと期待されるものです。

```ts
   Data:

   {
       disable_active_migration?:boolean,

       max_idle_timeout?:uint64,
       max_udp_payload_size?:uint32,
       active_connection_id_limit?:uint32,

       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,
   }
```

`parameter_set` と同じように、このイベントには仕様書では記述されていない追加のフィールドやカスタムパラメータを持つことが可能です。

### packet_sent
Importance: Core

このイベントには、送信されるQUIC Packetの情報が含まれます。具体的には、PacketHeaderの情報、そのQUIC Packetに含まれるQUIC Frame などがあります。

```ts
Data:
{
    header:PacketHeader,

    frames?:Array<QuicFrame>, // see appendix for the definitions

    is_coalesced?:boolean, // default value is false

    retry_token?:Token, // only if header.packet_type === retry

    stateless_reset_token?:bytes, // only if header.packet_type === stateless_reset. Is always 128 bits in length.

    supported_versions:Array<bytes>, // only if header.packet_type === version_negotiation

    raw?:RawInfo,
    datagram_id?:uint32
}
```

このイベントには以下のようなトリガーが想定されています。
*  "retransmit_reordered" // draft-23 5.1.1
*  "retransmit_timeout" // draft-23 5.1.2
*  "pto_probe" // draft-23 5.3.1
*  "retransmit_crypto" // draft-19 6.2
*  "cc_bandwidth_probe" // needed for some CCs to figure out
      bandwidth allocations when there are no normal sends


### packet_received
Importance: Core

このイベントには、送信されるQUIC Packetの情報が含まれます。
具体的には、PacketHeaderの情報、そのQUIC Packetに含まれるQUIC Frame などがあります。


```ts
   Data:
{
    header:PacketHeader,

    frames?:Array<QuicFrame>, // see appendix for the definitions

    is_coalesced?:boolean,

    retry_token?:Token, // only if header.packet_type === retry

    stateless_reset_token?:bytes, // only if header.packet_type === stateless_reset. Is always 128 bits in length.

    supported_versions:Array<bytes>, // only if header.packet_type === version_negotiation

    raw?:RawInfo,
    datagram_id?:uint32
}
```

以下のようなトリガーが想定されています。
*  "keys_available": パケットがバッファされたタイミング。そのタイミングで復号可能になるため。


### packet_dropped
Importance: Base

このイベントはQUICレベルのパケットのドロップが、部分的に解析した後、あるいは、解析無しで見つかったことを表します。

```ts
   Data:

{
    header?:PacketHeader, // primarily packet_type should be filled here, as other fields might not be parseable

    raw?:RawInfo,
    datagram_id?:uint32
}
```

このイベントに対しては、デバッグの助けになるので、`trigger` フィールドはセットされるべきです。

`trigger` フィールドにセットされる値は、以下のようなものが想定されています。
*  "key_unavailable"
*  "unknown_connection_id"
*  "header_parse_error"
*  "payload_decrypt_error"
*  "protocol_violation"
*  "dos_prevention"
*  "unsupported_version"
*  "unexpected_packet"
*  "unexpected_source_connection_id"
*  "unexpected_version"
*  "duplicate"
*  "invalid_initial"

### packet_buffered
Importance: Base

このイベントは、パケットがバッファリングされている時に、処理されていないことを記録するために使います。典型的には、パケットの解析が終わっていないので、生の情報をログする形になります。

```ts
   Data:
{
    header?:PacketHeader, // primarily packet_type and possible packet_number should be filled here, as other elements might not be available yet

    raw?:RawInfo,
    datagram_id?:uint32
}
```

以下のようなトリガーが想定されています。
*  "backpressure":  パーサーの処理が追いつかないことを示し、後の処理のためにパケットを一時的にバッファします。
*  "keys_unavailable": 適切な鍵がないため複合ができない場合

### packets_acked
Importance: Extra

このイベントは送信した（グループの）QUICパケット（複数）がリモートのピアによってackされた場合にログに記録します。

この情報は、ACKフレームの中身から推測ができます。しかし、ACKフレームによって、パケットがACKされたかを確認しようとした場合、繰り返し同じ範囲が含まれるため、あるパケットが初めてACKされたのがそのACKフレームなのかを判断するロジックが必要になります。

`packet_acked` イベントによってそれを回避することが可能になります。

```ts
   Data:
 { 
   packet_number_space?:PacketNumberSpace,
   packet_numbers?:Array<uint64> } 
```

もし、packet_number_spaceが捨てられた場合、PacketNumberSpace.application_dataのデフォルトの値を仮定します。なぜなら、それが一般的に最もよく使用されるQUICのパケットだからです。

### datagrams_sent
Importance: Extra

UDPレベルのデータグラムをソケットにパスしたときにログに書き込みます。(Datagram拡張ではありません）
これにより、QUICのパケットバッファがどのようにOSに渡されているかが分かります。

```ts
   Data:
{
    count?:uint16, // to support passing multiple at once
    raw?:Array<RawInfo>, // RawInfo:length field indicates total length of the datagrams, including UDP header length

    datagram_ids?:Array<uint32>
}
```

QUIC自体にはdatagram_idのコンセプトはありません。

このフィールドは、qlogレベルで、複数のQUICパケットがUDPのデータグラムでどのように融合されたのかトラッキングするための、qlog特有のものになります。

これは、QUICハンドシェイクにとって重要なオプションになります。実装では、ユニークIDをそれぞれのデータグラムに割り当て、どのパケットが同じデータグラムに融合されたのかを記録します。

パケットの融合は典型的にはハンドシェイクの時に起きるため（少なくとも一つlong header packetを必要とする）、このイベントはほとんどオーバーヘッドなしで扱えるようです。

### datagrams_received
Importance: Extra

1または複数のUDPレベルのデータグラムを受信したときに使います。
どのようにデータグラムがOSからユーザースペースに渡されているかを判断するのに役に立ちます。

```ts
   Data:

{
    count?:uint16, // to support passing multiple at once
    raw?:Array<RawInfo>, // RawInfo:length field indicates total length of the datagrams, including UDP header length

    datagram_ids?:Array<uint32>
}
```

### datagram_dropped
Importance: Extra

UDP-levelのデータグラムがドロップしたときに、使われます。
これは典型的には、validなQUICパケットを含んでいない場合に使われます。（そのような場合は`packet_dropped`が使われます。）

```ts
   Data:
   {
       raw?:RawInfo
   }
```

### stream_state_updated
Importance: Base

このイベントは、内部のストリームの状態が更新された時に発行されます。

draft-23のセクション3に書かれているように、多くの場合はいくつかのタイプのフレームの情報を元に判断します。
しかし、明示的なシグナルがあることでこの判断が行いやすくなります。

```ts
   Data:
{
    stream_id:uint64,
    stream_type?:"unidirectional"|"bidirectional", // mainly useful when opening the stream

    old?:StreamState,
    new:StreamState,

    stream_side?:"sending"|"receiving"
}

enum StreamState {
    // bidirectional stream states, draft-23 3.4.
    idle,
    open,
    half_closed_local,
    half_closed_remote,
    closed,

    // sending-side stream states, draft-23 3.1.
    ready,
    send,
    data_sent,
    reset_sent,
    reset_received,

    // receive-side stream states, draft-23 3.2.
    receive,
    size_known,
    data_read,
    reset_read,

    // both-side states
    data_received,

    // qlog-defined
    destroyed // memory actually freed
}
```

QUICの実装では、より細かいストリームの状態（例：data_sent、reset_received）ではなく、簡略化された双方向（HTTP/2-alike）のストリームの状態（例：idle、open、closed）を主に記録すべきです。 後者は主により詳細なデバッグのためのものです。 ツールは両方のタイプを同等に扱うことができるべきです。

### frames_processed
Importance: Extra

`packet_received`は受信したタイミングですが、このイベントは、QUICフレームを処理して適用した結果を記録できるようです。例えば、

このイベントの目的は、特定の目的のために大量にイベントが定義されるのを防ぐためにあります。
例えば、`packet_acknowledged`, `flow_control_updated`, `stream_data_received` といったものを個別に定義する場合が考えられます。

`packet_received`のようにパケットレベルの詳細を記録することなく、このタイプの情報を（選択的に）記録する機会を実装に与えたいという意図があります。

ほとんどの場合、実装の内部状態にフレームを適用した効果はそのフレームの内容から推測できるため、これらのイベントを「`frames_processed`」イベントに集約しています。

このイベントは、パースの直接の結果ではなく内部状態が変わったことシグナルに使うことができます。例えば、フレームがパースされ、データがバッファに入れられ、そののちに処理されたあとで、このイベントを記録します。

`packet_received`にはすべてのパケットの構成要素を含まれているので、それを実装する場合は`frame_processed`はログされることを予期しません。むしろ、すべてのパケットをログしたくない、あるいは、フレームが処理された場合追加の情報を明示的に出したいにこのイベントが使えます。

いくつかのイベントに対して、このアプローチは情報を失います（例えば、暗号レベルのパケットのAck?）。もしそういった情報が重要なら`packet_received`を使うべきです。

いくつかの実装では、`packet_sent`や`packet_received`イベントを使ってもフレームを直接ログするのは難しいです。
その場合、このイベントが、packet_numberフィールドを直接含み、明示的に`packet_sent`、`packet_received`とリンクされます。

```ts
   Data:

   {
       frames:Array<QuicFrame>, // see appendix for the definitions

       packet_number?:uint64
   }
```

### data_moved
Importance: Base

例えば、HTTPなどのアプリケーションプロトコルからQUICのストリームバッファへの受け渡しや、アプリケーションプロトコル間（HTTPとユーザーのプロトコルの間）のデータの移動などのデータが異なるレイヤを移動しているときに使われます。

これによりデータのフローが明らかになり、どのくらいの間バッファにデータが滞留しているかや、それによるそれぞれのレイヤのオーバーヘッドが分かります。

例えば、QUICのストリームに渡されたデータがアプリケーションプロトコルに即座に渡されたか（例えば受信したパケット毎に渡されているか）のか、巨大なバッチ（すべてのクイックパケットが最初に処理されてそれからアプリケーションレイヤが新しく利用可能になったストリームのデータを読み込む）として扱われたのかが明確になります。

これにより、ボトルネックやスケジューリングの問題が明らかにできます。

```ts
   Data:

{
    stream_id?:uint64,
    offset?:uint64,
    length?:uint64, // byte length of the moved data

    from?:string, // typically: use either of "user","application","transport","network"
    to?:string, // typically: use either of "user","application","transport","network"

    data?:bytes // raw bytes that were transferred
}
```

"direction"フィールド("up"/"down") はデータフローを記述するためには使われません。これは、いくつかの最適化で、データが独立したレイヤをスキップするからです。

さらに、"from"、"to"によって、柔軟な、概念的なレイヤ間のデータの渡し方を定義できます。
例えば、QUIC CRYPTフレームがTLSレイヤに渡される、あるいは、HTTP/3からQPACKに渡される、といったことが記述できます。

このイベントタイプは、transportのカテゴリにありますが、実際に、他の例やでも適用することができます。
これによって、いくつかの抽象化の漏れが起きます（例えば、ストリームIDあるいはストリームオフセットがロギングポイントで使えない、あるいは、rawデータがバイトアレイに含まれない）。
このような場合、実装は新しい、in-contextフィールドを手動のデバッグのために定義することが可能です。


## recovery
`recovery`のカテゴリには、ロス検出や輻輳制御に関連するイベントが定義されています。
おそらく、[QUIC Loss Detection and Congestion Control](https://datatracker.ietf.org/doc/html/rfc9002) に関連するものをまとめているのではないかと思います。

|event type|Importance| サマリー|
|-|-|-|
|parameters_set|Base|ロス検出や輻輳制御に関するパラメータを記録します  |
|metrics_updated|Core|1または複数のリカバリ用のメトリクスに変更があったことを記録します   |
|congestion_state_updated|Base|輻輳制御が何らかの新しい状態に入ったことや振る舞いが変わったことを記録します   |
|loss_timer_updated|Extra|リカバリロスタイマーが変更したときに発行されます   |
|packet_lost|Core   |パケットロスが検出されたときに発行されます|
|marked_for_retransmit|Extra|どのデータがパケットロスにより再走されたものかをマークします |


このカテゴリのほとんどのイベントは、異なるリカバリと多くの輻輳制御のアルゴリズムの方法をサポートするために汎用的に作られています。

したがって、ツールを作る場合はこれらのイベントに不明なフィールドがあったとしてもサポートと可視化する努力をするべきと書かれています（例えば、可視化の時に、未知の輻輳制御の状態名をタイムライン上にプロットできるようにする）。

### parameters_set
Importance: Base

このイベントは、ロス検出と輻輳制御に関する初期のパラメータをひとまとめにしています。

これらの設定は、典型的に一度設定されると変わりませんが、実装で何らかの理由で更新されることがあります。その場合、parameter_setのログを2回書き込むことがあるかもしれません。

```ts
   Data:

{
    // Loss detection, see recovery draft-23, Appendix A.2
    reordering_threshold?:uint16, // in amount of packets
    time_threshold?:float, // as RTT multiplier
    timer_granularity?:uint16, // in ms
    initial_rtt?:float, // in ms

    // congestion control, Appendix B.1.
    max_datagram_size?:uint32, // in bytes // Note: this could be updated after pmtud
    initial_congestion_window?:uint64, // in bytes
    minimum_congestion_window?:uint32, // in bytes // Note: this could change when max_datagram_size changes
    loss_reduction_factor?:float,
    persistent_congestion_threshold?:uint16 // as PTO multiplier
}
```

このイベントは異なるリカバリの方法をサポートするためにここでは記述されていないフィールドを持つかもしれません。

### metrics_updated
Importance: Core

このイベントは、１または複数のリカバリ用のメトリクスの変更があった場合に発行されます。

このイベントグループは、一度に起きたあるいは同時に起きたすべてのメトリクスの更新をグループにするべきです。（例えばmin_rttとsmoothed_rttが同時に変更されたら、一つのmetrics_updated エントリに入れます）。

結果、`metric_updated` イベントは、リストされたメトリクスから少なくとも一つのものが含まれていることが保証されます。

```ts
   Data:
{
    // Loss detection, see recovery draft-23, Appendix A.3
    min_rtt?:float, // in ms or us, depending on the overarching qlog's configuration
    smoothed_rtt?:float, // in ms or us, depending on the overarching qlog's configuration
    latest_rtt?:float, // in ms or us, depending on the overarching qlog's configuration
    rtt_variance?:float, // in ms or us, depending on the overarching qlog's configuration

    pto_count?:uint16,

    // Congestion control, Appendix B.2.
    congestion_window?:uint64, // in bytes
    bytes_in_flight?:uint64,

    ssthresh?:uint64, // in bytes

    // qlog defined
    packets_in_flight?:uint64, // sum of all packet number spaces

    pacing_rate?:uint64 // in bps
}
```

ロギングを簡単にするためには値の更新がなかったパラメータについてもロギングしたほうがよいかもしれないです。しかし、アプリケーションは1回、実際に更新されたものだけをログするべきです。

また、このイベントは未定義のフィールドを含むかもしれません。

### congestion_state_updated
Importance: Base

このイベントは、輻輳制御が何らかの新しい状態に入ったことや振る舞いが変わったことを表します。

このイベントの定義は、異なる輻輳制御アルゴリズムをサポートするために汎用的に定義されています。

例えば、[Recovery](https://datatracker.ietf.org/doc/html/rfc9002) に定義されたアルゴリズム ("enhanced" New Reno) は以下のような状態が定義されます。

*  slow_start
*  congestion_avoidance
*  application_limited
*  recovery

```ts
   Data:

   {
       old?:string,
       new:string
   }
```

トリガーフィールドは、状態変化を起こすものが複数ある場合は保存するべきです。しかし、単一のイベントのみによって起きる場合無視することができます。例えば、slow startはssthreshが超えた場合のみ抜け出します。

"enhanced" New Reno の場合は以下のようなトリガーが考えられます。
*  persistent_congestion
*  ECN

### loss_timer_updated
Importance: Extra

このイベントは、リカバリロスタイマーが変更したときに発行されます。

おもに3つのタイミングがあります。

* set: タイマーを次にイベントが発生するdelta timeoutにセットします。
* expired: delta taimeoutが切れた場合
* canceld: タイマーがキャンセルされた場合（すべてのパケットがackされて、アイドル状態になる)

アクティブなタイマーのタイムアウトを示すために、新しい"set"イベントが使われる。

```ts
   Data:
{
    timer_type?:"ack"|"pto", // called "mode" in draft-23 A.9.
    packet_number_space?: PacketNumberSpace,

    event_type:"set"|"expired"|"cancelled",

    delta?:float // if event_type === "set": delta time in ms or us (see configuration) from this event's timestamp until when the timer will trigger
}
```

複数のタイマーを使うような場合は現在検討中のようです。


### packet_lost
Importance: Core

このイベントは、パケットがロス検出によってロスされたと判断されたときに発行されます。

```ts
   Data:
{
    header?:PacketHeader, // should include at least the packet_type and packet_number

    // not all implementations will keep track of full packets, so these are optional
    frames?:Array<QuicFrame> // see appendix for the definitions
}
```

トリガーは、以下のようなものが想定されます。
*  "reordering_threshold",
*  "time_threshold"
*  "pto_expired" // draft-23 section 5.3.1, MAY

### marked_for_retransmit
Importance: Extra

このイベントは、どのデータがパケットロスによる再送されたものをマークします。

`frame_processed`と同様の理由で、異なるイベントを少なくするために、すべてのタイプの再走されるデータを単一のイベントで定義します。

フルパケットあるいはフレームを直接再送するような実装は、このログをロスしたパケット全体を記録するために使えます。
（あるいは、このイベントは使わずに、`packet_lost`イベントを使います。）

より複雑な実装（例えば、送信中のストリームの範囲を記録している）場合や、フレーム全体を記録していない（例えばストリームのオフセットと長さを記録している）ような場合、それらの内部の振る舞いを適切にフレームに変換する必要があります。

```ts
   Data:
   {
       frames:Array<QuicFrame>, // see appendix for the definitions
   }
```


## QUIC data field definitions
enumなどの再利用可能なものはドキュメントの最後の[Appendix A](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#appendix-A) に定義されています。

### IPAddress

```ts
class IPAddress : string | bytes;
```

IPアドレスは、人間が読める形式か生のバイトデータのどちらも可能です。


### PacketType
```ts
   enum PacketType {
       initial,
       handshake,
       zerortt = "0RTT",
       onertt = "1RTT",
       retry,
       version_negotiation,
       stateless_reset,
       unknown
   }
```

### PacketNumberSpace

```ts
   enum PacketNumberSpace {
       initial,
       handshake,
       application_data
   }
```

### PacketHeader

```ts
class PacketHeader {
    // Note: short vs long header is implicit through PacketType

    packet_type: PacketType;
    packet_number: uint64;

    flags?: uint8; // the bit flags of the packet headers (spin bit, key update bit, etc. up to and including the packet number length bits if present) interpreted as a single 8-bit integer

    token?:Token; // only if packet_type == initial

    length?: uint16, // only if packet_type == initial || handshake || 0RTT. Signifies length of the packet_number plus the payload.

    // only if present in the header
    // if correctly using transport:connection_id_updated events,
    // dcid can be skipped for 1RTT packets
    version?: bytes; // e.g., "ff00001d" for draft-29
    scil?: uint8;
    dcil?: uint8;
    scid?: bytes;
    dcid?: bytes;
}
```

### Token

```ts
class Token {
    type?:"retry"|"resumption"|"stateless_reset";

    length?:uint32; // byte length of the token
    data?:bytes; // raw byte value of the token

    details?:any; // decoded fields included in the token (typically: peer's IP address, creation time)
}
```

initial packetで運ばれるトークンは、
①Retryパケットのretry token
②Stateless reset packetからのstateless reset token
③接続を再開するための、サーバーから提供されるNewTokenフレーム（アドレス検証プロセス）
のどれかです。

Retryとresumptionトークンは典型的にはメタデータにエンコードされ、妥当性を検証されます。しかし、このメタデータとフォーマットは実装依存です。なので、このフィールドは汎用的なdetailsというフィールドにされています。

### KeyType
```ts
   enum 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
   }
```

### QUIC Frames

```ts
type QuicFrame = PaddingFrame | PingFrame | AckFrame | ResetStreamFrame | StopSendingFrame | CryptoFrame | NewTokenFrame | StreamFrame | MaxDataFrame | MaxStreamDataFrame | MaxStreamsFrame | DataBlockedFrame | StreamDataBlockedFrame | StreamsBlockedFrame | NewConnectionIDFrame | RetireConnectionIDFrame | PathChallengeFrame | PathResponseFrame | ConnectionCloseFrame | HandshakeDoneFrame | UnknownFrame;
```

#### PaddingFrame
QUICでは、PADDINGフレームは1つの0バイトを表しています。論理的には、各パディングバイトがパディングフレームとして記録されます。

しかし、そうするとログのオーバーヘッドが大きくなってしまうため、実装は一つのPaddingFrameだけを発行し、`paload_length`プロパティでパケットに含まれるPADDINGバイトの量を表すことができます。


```ts
   class PaddingFrame{
       frame_type:string = "padding";

       length?:uint32; // total frame length, including frame header
       payload_length?:uint32;
   }
```

#### PingFrame

```ts
   class PingFrame{
       frame_type:string = "ping";

       length?:uint32; // total frame length, including frame header
       payload_length?:uint32;
   }
```

#### AckFrame
```ts
class AckFrame{
    frame_type:string = "ack";

    ack_delay?:float; // in ms

    // first number is "from": lowest packet number in interval
    // second number is "to": up to and including // highest packet number in interval
    // e.g., looks like [[1,2],[4,5]]
    acked_ranges?:Array<[uint64, uint64]|[uint64]>;

    // ECN (explicit congestion notification) related fields (not always present)
    ect1?:uint64;
    ect0?:uint64;
    ce?:uint64;

    length?:uint32; // total frame length, including frame header
    payload_length?:uint32;
}
```

AckFrame.acked_rangesは、順番になっていなくてもよいです。ログを出す側は[120,120]を[120]と出すべきです。ただし、ツールは両方対応できないといけません。

#### ResetStreamFrame

```ts
   class ResetStreamFrame{
       frame_type:string = "reset_stream";

       stream_id:uint64;
       error_code:ApplicationError | uint32;
       final_size:uint64; // in bytes

       length?:uint32; // total frame length, including frame header
       payload_length?:uint32;
   }
```

#### StopSendingFrame
```ts
   class StopSendingFrame{
       frame_type:string = "stop_sending";

       stream_id:uint64;
       error_code:ApplicationError | uint32;

       length?:uint32; // total frame length, including frame header
       payload_length?:uint32;
   }
```

####  CryptoFrame
```ts
   class CryptoFrame{
       frame_type:string = "crypto";

       offset:uint64;
       length:uint64;

       payload_length?:uint32;
   }
```

#### NewTokenFrame
```ts
   class NewTokenFrame{
     frame_type:string = "new_token";

     token:Token
   }
```

#### StreamFrame
```ts
class StreamFrame{
    frame_type:string = "stream";

    stream_id:uint64;

    // These two MUST always be set
    // If not present in the Frame type, log their default values
    offset:uint64;
    length:uint64;

    // this MAY be set any time, but MUST only be set if the value is "true"
    // if absent, the value MUST be assumed to be "false"
    fin?:boolean;

    raw?:bytes;
}
```

#### MaxDataFrame
```ts
   class MaxDataFrame{
     frame_type:string = "max_data";

     maximum:uint64;
   }
```

#### MaxStreamDataFrame
```ts
   class MaxStreamDataFrame{
     frame_type:string = "max_stream_data";

     stream_id:uint64;
     maximum:uint64;
   }
```

#### MaxStreamsFrame
```ts
   class MaxStreamsFrame{
     frame_type:string = "max_streams";

     stream_type:string = "bidirectional" | "unidirectional";
     maximum:uint64;
   }
```

#### DataBlockedFrame
```ts
   class DataBlockedFrame{
     frame_type:string = "data_blocked";

     limit:uint64;
   }
```

#### StreamDataBlockedFrame
```ts
   class StreamDataBlockedFrame{
     frame_type:string = "stream_data_blocked";

     stream_id:uint64;
     limit:uint64;
   }
```

#### StreamsBlockedFrame
```ts
   class StreamsBlockedFrame{
     frame_type:string = "streams_blocked";

     stream_type:string = "bidirectional" | "unidirectional";
     limit:uint64;
   }
```

#### NewConnectionIDFrame
```ts
   class NewConnectionIDFrame{
     frame_type:string = "new_connection_id";

     sequence_number:uint32;
     retire_prior_to:uint32;

     connection_id_length?:uint8;
     connection_id:bytes;

     stateless_reset_token?:Token;
   }
```

#### RetireConnectionIDFrame
```ts
   class RetireConnectionIDFrame{
     frame_type:string = "retire_connection_id";

     sequence_number:uint32;
   }
```

#### PathChallengeFrame
```ts
   class PathChallengeFrame{
     frame_type:string = "path_challenge";

     data?:bytes; // always 64-bit
   }
```

#### PathResponseFrame
```ts
   class PathResponseFrame{
     frame_type:string = "path_response";

     data?:bytes; // always 64-bit
   }
```

#### ConnectionCloseFrame
raw_error_codeは、実際には数値のコードです。これは、一部のエラータイプが複数のコードにまたがっている場合に便利です。

```ts
type ErrorSpace = "transport" | "application";

class ConnectionCloseFrame{
    frame_type:string = "connection_close";

    error_space?:ErrorSpace;
    error_code?:TransportError | ApplicationError | uint32;
    raw_error_code?:uint32;
    reason?:string;

    trigger_frame_type?:uint64 | string; // For known frame types, the appropriate "frame_type" string. For unknown frame types, the hex encoded identifier value
}
```

#### HandshakeDoneFrame
```ts
   class HandshakeDoneFrame{
     frame_type:string = "handshake_done";
   }
```

#### UnknownFrame
```ts
   class UnknownFrame{
       frame_type:string = "unknown";
       raw_frame_type:uint64;

       raw_length?:uint32;
       raw?:bytes;
   }
```

#### TransportError
```ts
   enum 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
   }
```

#### CryptoError
このエラーは、TLSのドキュメントに「TLSアラートは、1バイトのエラーコードをQUICエラーコードに変換することでQUIC接続エラーに変換される。このアラートは、0x100からQUICのエラーコードのために予約される」と記されています。

このアプローチは、事前に定義されたenumです。`crypto_error`文字列は、hex-encodedされたTLSアラートを表すダイナミックコンポーネントとして定義します。

```ts
   enum CryptoError {
       crypto_error_{TLS_ALERT}
   }
```

# 終わりに
長くなりましたが、「QUIC event definitions for qlog」でこれから定義しようとしている、qlogにQUICのイベントを記録するための情報の定義を紹介しました。

個人的には、ログされるイベントから規格の理解を深めることもできるのではないかと思いました。