-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the structure for generating and writing qlog events. Events are generated as slog events using the structure of the qlog events (draft-ietf-quic-qlog-quic-events-03). The qlog package contains a slog Handler implementation that converts the quic package events to qlog JSON. This CL generates events for connection creation and closure. Future CLs will add additional events. Events follow draft-ietf-quic-qlog-quic-events-03, which is the most recent draft supported by the qvis visualization tool. https://www.ietf.org/archive/id/draft-ietf-quic-qlog-main-schema-04.html https://www.ietf.org/archive/id/draft-ietf-quic-qlog-quic-events-03.html For golang/go#58547 Change-Id: I5fb1b7653d0257cb86726bd5bc9e8775da74686a Reviewed-on: https://go-review.googlesource.com/c/net/+/537936 Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jonathan Amsterdam <jba@google.com>
- Loading branch information
Showing
14 changed files
with
1,216 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
// Copyright 2023 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
//go:build go1.21 | ||
|
||
package quic | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"log/slog" | ||
"net/netip" | ||
) | ||
|
||
// Log levels for qlog events. | ||
const ( | ||
// QLogLevelFrame includes per-frame information. | ||
// When this level is enabled, packet_sent and packet_received events will | ||
// contain information on individual frames sent/received. | ||
QLogLevelFrame = slog.Level(-6) | ||
|
||
// QLogLevelPacket events occur at most once per packet sent or received. | ||
// | ||
// For example: packet_sent, packet_received. | ||
QLogLevelPacket = slog.Level(-4) | ||
|
||
// QLogLevelConn events occur multiple times over a connection's lifetime, | ||
// but less often than the frequency of individual packets. | ||
// | ||
// For example: connection_state_updated. | ||
QLogLevelConn = slog.Level(-2) | ||
|
||
// QLogLevelEndpoint events occur at most once per connection. | ||
// | ||
// For example: connection_started, connection_closed. | ||
QLogLevelEndpoint = slog.Level(0) | ||
) | ||
|
||
func (c *Conn) logEnabled(level slog.Level) bool { | ||
return c.log != nil && c.log.Enabled(context.Background(), level) | ||
} | ||
|
||
// slogHexstring returns a slog.Attr for a value of the hexstring type. | ||
// | ||
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-main-schema-04.html#section-1.1.1 | ||
func slogHexstring(key string, value []byte) slog.Attr { | ||
return slog.String(key, hex.EncodeToString(value)) | ||
} | ||
|
||
func slogAddr(key string, value netip.Addr) slog.Attr { | ||
return slog.String(key, value.String()) | ||
} | ||
|
||
func (c *Conn) logConnectionStarted(originalDstConnID []byte, peerAddr netip.AddrPort) { | ||
if c.config.QLogLogger == nil || | ||
!c.config.QLogLogger.Enabled(context.Background(), QLogLevelEndpoint) { | ||
return | ||
} | ||
var vantage string | ||
if c.side == clientSide { | ||
vantage = "client" | ||
originalDstConnID = c.connIDState.originalDstConnID | ||
} else { | ||
vantage = "server" | ||
} | ||
// A qlog Trace container includes some metadata (title, description, vantage_point) | ||
// and a list of Events. The Trace also includes a common_fields field setting field | ||
// values common to all events in the trace. | ||
// | ||
// Trace = { | ||
// ? title: text | ||
// ? description: text | ||
// ? configuration: Configuration | ||
// ? common_fields: CommonFields | ||
// ? vantage_point: VantagePoint | ||
// events: [* Event] | ||
// } | ||
// | ||
// To map this into slog's data model, we start each per-connection trace with a With | ||
// call that includes both the trace metadata and the common fields. | ||
// | ||
// This means that in slog's model, each trace event will also include | ||
// the Trace metadata fields (vantage_point), which is a divergence from the qlog model. | ||
c.log = c.config.QLogLogger.With( | ||
// The group_id permits associating traces taken from different vantage points | ||
// for the same connection. | ||
// | ||
// We use the original destination connection ID as the group ID. | ||
// | ||
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-main-schema-04.html#section-3.4.6 | ||
slogHexstring("group_id", originalDstConnID), | ||
slog.Group("vantage_point", | ||
slog.String("name", "go quic"), | ||
slog.String("type", vantage), | ||
), | ||
) | ||
localAddr := c.listener.LocalAddr() | ||
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-quic-events-03.html#section-4.2 | ||
c.log.LogAttrs(context.Background(), QLogLevelEndpoint, | ||
"connectivity:connection_started", | ||
slogAddr("src_ip", localAddr.Addr()), | ||
slog.Int("src_port", int(localAddr.Port())), | ||
slogHexstring("src_cid", c.connIDState.local[0].cid), | ||
slogAddr("dst_ip", peerAddr.Addr()), | ||
slog.Int("dst_port", int(peerAddr.Port())), | ||
slogHexstring("dst_cid", c.connIDState.remote[0].cid), | ||
) | ||
} | ||
|
||
func (c *Conn) logConnectionClosed() { | ||
if !c.logEnabled(QLogLevelEndpoint) { | ||
return | ||
} | ||
err := c.lifetime.finalErr | ||
trigger := "error" | ||
switch e := err.(type) { | ||
case *ApplicationError: | ||
// TODO: Distinguish between peer and locally-initiated close. | ||
trigger = "application" | ||
case localTransportError: | ||
if e.code == errNo { | ||
trigger = "clean" | ||
} | ||
case peerTransportError: | ||
if e.code == errNo { | ||
trigger = "clean" | ||
} | ||
default: | ||
switch err { | ||
case errStatelessReset: | ||
trigger = "stateless_reset" | ||
} | ||
// TODO: idle_timeout, handshake_timeout | ||
} | ||
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-quic-events-03.html#section-4.3 | ||
c.log.LogAttrs(context.Background(), QLogLevelEndpoint, | ||
"connectivity:connection_closed", | ||
slog.String("trigger", trigger), | ||
) | ||
} |
Oops, something went wrong.