1
2
3
4
5
6
7 package quic
8
9 import (
10 "context"
11 "encoding/hex"
12 "log/slog"
13 "net/netip"
14 "time"
15 )
16
17
18 const (
19
20
21
22 QLogLevelFrame = slog.Level(-6)
23
24
25
26
27 QLogLevelPacket = slog.Level(-4)
28
29
30
31
32
33 QLogLevelConn = slog.Level(-2)
34
35
36
37
38 QLogLevelEndpoint = slog.Level(0)
39 )
40
41 func (c *Conn) logEnabled(level slog.Level) bool {
42 return logEnabled(c.log, level)
43 }
44
45 func logEnabled(log *slog.Logger, level slog.Level) bool {
46 return log != nil && log.Enabled(context.Background(), level)
47 }
48
49
50
51
52 func slogHexstring(key string, value []byte) slog.Attr {
53 return slog.String(key, hex.EncodeToString(value))
54 }
55
56 func slogAddr(key string, value netip.Addr) slog.Attr {
57 return slog.String(key, value.String())
58 }
59
60 func (c *Conn) logConnectionStarted(originalDstConnID []byte, peerAddr netip.AddrPort) {
61 if c.config.QLogLogger == nil ||
62 !c.config.QLogLogger.Enabled(context.Background(), QLogLevelEndpoint) {
63 return
64 }
65 var vantage string
66 if c.side == clientSide {
67 vantage = "client"
68 originalDstConnID = c.connIDState.originalDstConnID
69 } else {
70 vantage = "server"
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 c.log = c.config.QLogLogger.With(
91
92
93
94
95
96
97 slogHexstring("group_id", originalDstConnID),
98 slog.Group("vantage_point",
99 slog.String("name", "go quic"),
100 slog.String("type", vantage),
101 ),
102 )
103 localAddr := c.endpoint.LocalAddr()
104
105 c.log.LogAttrs(context.Background(), QLogLevelEndpoint,
106 "connectivity:connection_started",
107 slogAddr("src_ip", localAddr.Addr()),
108 slog.Int("src_port", int(localAddr.Port())),
109 slogHexstring("src_cid", c.connIDState.local[0].cid),
110 slogAddr("dst_ip", peerAddr.Addr()),
111 slog.Int("dst_port", int(peerAddr.Port())),
112 slogHexstring("dst_cid", c.connIDState.remote[0].cid),
113 )
114 }
115
116 func (c *Conn) logConnectionClosed() {
117 if !c.logEnabled(QLogLevelEndpoint) {
118 return
119 }
120 err := c.lifetime.finalErr
121 trigger := "error"
122 switch e := err.(type) {
123 case *ApplicationError:
124
125 trigger = "application"
126 case localTransportError:
127 switch err {
128 case errHandshakeTimeout:
129 trigger = "handshake_timeout"
130 default:
131 if e.code == errNo {
132 trigger = "clean"
133 }
134 }
135 case peerTransportError:
136 if e.code == errNo {
137 trigger = "clean"
138 }
139 default:
140 switch err {
141 case errIdleTimeout:
142 trigger = "idle_timeout"
143 case errStatelessReset:
144 trigger = "stateless_reset"
145 }
146 }
147
148 c.log.LogAttrs(context.Background(), QLogLevelEndpoint,
149 "connectivity:connection_closed",
150 slog.String("trigger", trigger),
151 )
152 }
153
154 func (c *Conn) logPacketDropped(dgram *datagram) {
155 c.log.LogAttrs(context.Background(), QLogLevelPacket,
156 "connectivity:packet_dropped",
157 )
158 }
159
160 func (c *Conn) logLongPacketReceived(p longPacket, pkt []byte) {
161 var frames slog.Attr
162 if c.logEnabled(QLogLevelFrame) {
163 frames = c.packetFramesAttr(p.payload)
164 }
165 c.log.LogAttrs(context.Background(), QLogLevelPacket,
166 "transport:packet_received",
167 slog.Group("header",
168 slog.String("packet_type", p.ptype.qlogString()),
169 slog.Uint64("packet_number", uint64(p.num)),
170 slog.Uint64("flags", uint64(pkt[0])),
171 slogHexstring("scid", p.srcConnID),
172 slogHexstring("dcid", p.dstConnID),
173 ),
174 slog.Group("raw",
175 slog.Int("length", len(pkt)),
176 ),
177 frames,
178 )
179 }
180
181 func (c *Conn) log1RTTPacketReceived(p shortPacket, pkt []byte) {
182 var frames slog.Attr
183 if c.logEnabled(QLogLevelFrame) {
184 frames = c.packetFramesAttr(p.payload)
185 }
186 dstConnID, _ := dstConnIDForDatagram(pkt)
187 c.log.LogAttrs(context.Background(), QLogLevelPacket,
188 "transport:packet_received",
189 slog.Group("header",
190 slog.String("packet_type", packetType1RTT.qlogString()),
191 slog.Uint64("packet_number", uint64(p.num)),
192 slog.Uint64("flags", uint64(pkt[0])),
193 slogHexstring("dcid", dstConnID),
194 ),
195 slog.Group("raw",
196 slog.Int("length", len(pkt)),
197 ),
198 frames,
199 )
200 }
201
202 func (c *Conn) logPacketSent(ptype packetType, pnum packetNumber, src, dst []byte, pktLen int, payload []byte) {
203 var frames slog.Attr
204 if c.logEnabled(QLogLevelFrame) {
205 frames = c.packetFramesAttr(payload)
206 }
207 var scid slog.Attr
208 if len(src) > 0 {
209 scid = slogHexstring("scid", src)
210 }
211 c.log.LogAttrs(context.Background(), QLogLevelPacket,
212 "transport:packet_sent",
213 slog.Group("header",
214 slog.String("packet_type", ptype.qlogString()),
215 slog.Uint64("packet_number", uint64(pnum)),
216 scid,
217 slogHexstring("dcid", dst),
218 ),
219 slog.Group("raw",
220 slog.Int("length", pktLen),
221 ),
222 frames,
223 )
224 }
225
226
227
228
229
230
231
232 func (c *Conn) packetFramesAttr(payload []byte) slog.Attr {
233 var frames []slog.Value
234 for len(payload) > 0 {
235 f, n := parseDebugFrame(payload)
236 if n < 0 {
237 break
238 }
239 payload = payload[n:]
240 switch f := f.(type) {
241 case debugFrameAck:
242
243
244
245
246
247
248
249
250
251 ackDelay := time.Duration(-1)
252 if c.peerAckDelayExponent >= 0 {
253 ackDelay = f.ackDelay.Duration(uint8(c.peerAckDelayExponent))
254 }
255 frames = append(frames, slog.AnyValue(debugFrameScaledAck{
256 ranges: f.ranges,
257 ackDelay: ackDelay,
258 }))
259 default:
260 frames = append(frames, slog.AnyValue(f))
261 }
262 }
263 return slog.Any("frames", frames)
264 }
265
266 func (c *Conn) logPacketLost(space numberSpace, sent *sentPacket) {
267 c.log.LogAttrs(context.Background(), QLogLevelPacket,
268 "recovery:packet_lost",
269 slog.Group("header",
270 slog.String("packet_type", sent.ptype.qlogString()),
271 slog.Uint64("packet_number", uint64(sent.num)),
272 ),
273 )
274 }
275
View as plain text