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