github.com/tumi8/quic-go@v0.37.4-tum/qlog/qlog.go (about) 1 package qlog 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "log" 8 "net" 9 "runtime/debug" 10 "sync" 11 "time" 12 13 "github.com/tumi8/quic-go/noninternal/protocol" 14 "github.com/tumi8/quic-go/noninternal/utils" 15 "github.com/tumi8/quic-go/noninternal/wire" 16 "github.com/tumi8/quic-go/logging" 17 18 "github.com/francoispqt/gojay" 19 ) 20 21 // Setting of this only works when quic-go is used as a library. 22 // When building a binary from this repository, the version can be set using the following go build flag: 23 // -ldflags="-X github.com/tumi8/quic-go/qlog.quicGoVersion=foobar" 24 var quicGoVersion = "(devel)" 25 26 func init() { 27 if quicGoVersion != "(devel)" { // variable set by ldflags 28 return 29 } 30 info, ok := debug.ReadBuildInfo() 31 if !ok { // no build info available. This happens when quic-go is not used as a library. 32 return 33 } 34 for _, d := range info.Deps { 35 if d.Path == "github.com/tumi8/quic-go" { 36 quicGoVersion = d.Version 37 if d.Replace != nil { 38 if len(d.Replace.Version) > 0 { 39 quicGoVersion = d.Version 40 } else { 41 quicGoVersion += " (replaced)" 42 } 43 } 44 break 45 } 46 } 47 } 48 49 const eventChanSize = 50 50 51 type connectionTracer struct { 52 mutex sync.Mutex 53 54 w io.WriteCloser 55 odcid protocol.ConnectionID 56 perspective protocol.Perspective 57 referenceTime time.Time 58 59 events chan event 60 encodeErr error 61 runStopped chan struct{} 62 63 lastMetrics *metrics 64 } 65 66 var _ logging.ConnectionTracer = &connectionTracer{} 67 68 // NewConnectionTracer creates a new tracer to record a qlog for a connection. 69 func NewConnectionTracer(w io.WriteCloser, p protocol.Perspective, odcid protocol.ConnectionID) logging.ConnectionTracer { 70 t := &connectionTracer{ 71 w: w, 72 perspective: p, 73 odcid: odcid, 74 runStopped: make(chan struct{}), 75 events: make(chan event, eventChanSize), 76 referenceTime: time.Now(), 77 } 78 go t.run() 79 return t 80 } 81 82 func (t *connectionTracer) run() { 83 defer close(t.runStopped) 84 buf := &bytes.Buffer{} 85 enc := gojay.NewEncoder(buf) 86 tl := &topLevel{ 87 trace: trace{ 88 VantagePoint: vantagePoint{Type: t.perspective}, 89 CommonFields: commonFields{ 90 ODCID: t.odcid, 91 GroupID: t.odcid, 92 ReferenceTime: t.referenceTime, 93 }, 94 }, 95 } 96 if err := enc.Encode(tl); err != nil { 97 panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err)) 98 } 99 if err := buf.WriteByte('\n'); err != nil { 100 panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err)) 101 } 102 if _, err := t.w.Write(buf.Bytes()); err != nil { 103 t.encodeErr = err 104 } 105 enc = gojay.NewEncoder(t.w) 106 for ev := range t.events { 107 if t.encodeErr != nil { // if encoding failed, just continue draining the event channel 108 continue 109 } 110 if err := enc.Encode(ev); err != nil { 111 t.encodeErr = err 112 continue 113 } 114 if _, err := t.w.Write([]byte{'\n'}); err != nil { 115 t.encodeErr = err 116 } 117 } 118 } 119 120 func (t *connectionTracer) Close() { 121 if err := t.export(); err != nil { 122 log.Printf("exporting qlog failed: %s\n", err) 123 } 124 } 125 126 // export writes a qlog. 127 func (t *connectionTracer) export() error { 128 close(t.events) 129 <-t.runStopped 130 if t.encodeErr != nil { 131 return t.encodeErr 132 } 133 return t.w.Close() 134 } 135 136 func (t *connectionTracer) recordEvent(eventTime time.Time, details eventDetails) { 137 t.events <- event{ 138 RelativeTime: eventTime.Sub(t.referenceTime), 139 eventDetails: details, 140 } 141 } 142 143 func (t *connectionTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID protocol.ConnectionID) { 144 // ignore this event if we're not dealing with UDP addresses here 145 localAddr, ok := local.(*net.UDPAddr) 146 if !ok { 147 return 148 } 149 remoteAddr, ok := remote.(*net.UDPAddr) 150 if !ok { 151 return 152 } 153 t.mutex.Lock() 154 t.recordEvent(time.Now(), &eventConnectionStarted{ 155 SrcAddr: localAddr, 156 DestAddr: remoteAddr, 157 SrcConnectionID: srcConnID, 158 DestConnectionID: destConnID, 159 }) 160 t.mutex.Unlock() 161 } 162 163 func (t *connectionTracer) NegotiatedVersion(chosen logging.VersionNumber, client, server []logging.VersionNumber) { 164 var clientVersions, serverVersions []versionNumber 165 if len(client) > 0 { 166 clientVersions = make([]versionNumber, len(client)) 167 for i, v := range client { 168 clientVersions[i] = versionNumber(v) 169 } 170 } 171 if len(server) > 0 { 172 serverVersions = make([]versionNumber, len(server)) 173 for i, v := range server { 174 serverVersions[i] = versionNumber(v) 175 } 176 } 177 t.mutex.Lock() 178 t.recordEvent(time.Now(), &eventVersionNegotiated{ 179 clientVersions: clientVersions, 180 serverVersions: serverVersions, 181 chosenVersion: versionNumber(chosen), 182 }) 183 t.mutex.Unlock() 184 } 185 186 func (t *connectionTracer) ClosedConnection(e error) { 187 t.mutex.Lock() 188 t.recordEvent(time.Now(), &eventConnectionClosed{e: e}) 189 t.mutex.Unlock() 190 } 191 192 func (t *connectionTracer) SentTransportParameters(tp *wire.TransportParameters) { 193 t.recordTransportParameters(t.perspective, tp) 194 } 195 196 func (t *connectionTracer) ReceivedTransportParameters(tp *wire.TransportParameters) { 197 t.recordTransportParameters(t.perspective.Opposite(), tp) 198 } 199 200 func (t *connectionTracer) RestoredTransportParameters(tp *wire.TransportParameters) { 201 ev := t.toTransportParameters(tp) 202 ev.Restore = true 203 204 t.mutex.Lock() 205 t.recordEvent(time.Now(), ev) 206 t.mutex.Unlock() 207 } 208 209 func (t *connectionTracer) recordTransportParameters(sentBy protocol.Perspective, tp *wire.TransportParameters) { 210 ev := t.toTransportParameters(tp) 211 ev.Owner = ownerLocal 212 if sentBy != t.perspective { 213 ev.Owner = ownerRemote 214 } 215 ev.SentBy = sentBy 216 217 t.mutex.Lock() 218 t.recordEvent(time.Now(), ev) 219 t.mutex.Unlock() 220 } 221 222 func (t *connectionTracer) toTransportParameters(tp *wire.TransportParameters) *eventTransportParameters { 223 var pa *preferredAddress 224 if tp.PreferredAddress != nil { 225 pa = &preferredAddress{ 226 IPv4: tp.PreferredAddress.IPv4, 227 PortV4: tp.PreferredAddress.IPv4Port, 228 IPv6: tp.PreferredAddress.IPv6, 229 PortV6: tp.PreferredAddress.IPv6Port, 230 ConnectionID: tp.PreferredAddress.ConnectionID, 231 StatelessResetToken: tp.PreferredAddress.StatelessResetToken, 232 } 233 } 234 return &eventTransportParameters{ 235 OriginalDestinationConnectionID: tp.OriginalDestinationConnectionID, 236 InitialSourceConnectionID: tp.InitialSourceConnectionID, 237 RetrySourceConnectionID: tp.RetrySourceConnectionID, 238 StatelessResetToken: tp.StatelessResetToken, 239 DisableActiveMigration: tp.DisableActiveMigration, 240 MaxIdleTimeout: tp.MaxIdleTimeout, 241 MaxUDPPayloadSize: tp.MaxUDPPayloadSize, 242 AckDelayExponent: tp.AckDelayExponent, 243 MaxAckDelay: tp.MaxAckDelay, 244 ActiveConnectionIDLimit: tp.ActiveConnectionIDLimit, 245 InitialMaxData: tp.InitialMaxData, 246 InitialMaxStreamDataBidiLocal: tp.InitialMaxStreamDataBidiLocal, 247 InitialMaxStreamDataBidiRemote: tp.InitialMaxStreamDataBidiRemote, 248 InitialMaxStreamDataUni: tp.InitialMaxStreamDataUni, 249 InitialMaxStreamsBidi: int64(tp.MaxBidiStreamNum), 250 InitialMaxStreamsUni: int64(tp.MaxUniStreamNum), 251 PreferredAddress: pa, 252 MaxDatagramFrameSize: tp.MaxDatagramFrameSize, 253 } 254 } 255 256 func (t *connectionTracer) SentLongHeaderPacket(hdr *logging.ExtendedHeader, packetSize logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) { 257 t.sentPacket(*transformLongHeader(hdr), packetSize, hdr.Length, ack, frames) 258 } 259 260 func (t *connectionTracer) SentShortHeaderPacket(hdr *logging.ShortHeader, packetSize logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) { 261 t.sentPacket(*transformShortHeader(hdr), packetSize, 0, ack, frames) 262 } 263 264 func (t *connectionTracer) sentPacket(hdr gojay.MarshalerJSONObject, packetSize, payloadLen logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) { 265 numFrames := len(frames) 266 if ack != nil { 267 numFrames++ 268 } 269 fs := make([]frame, 0, numFrames) 270 if ack != nil { 271 fs = append(fs, frame{Frame: ack}) 272 } 273 for _, f := range frames { 274 fs = append(fs, frame{Frame: f}) 275 } 276 t.mutex.Lock() 277 t.recordEvent(time.Now(), &eventPacketSent{ 278 Header: hdr, 279 Length: packetSize, 280 PayloadLength: payloadLen, 281 Frames: fs, 282 }) 283 t.mutex.Unlock() 284 } 285 286 func (t *connectionTracer) ReceivedLongHeaderPacket(hdr *logging.ExtendedHeader, packetSize logging.ByteCount, frames []logging.Frame) { 287 fs := make([]frame, len(frames)) 288 for i, f := range frames { 289 fs[i] = frame{Frame: f} 290 } 291 header := *transformLongHeader(hdr) 292 t.mutex.Lock() 293 t.recordEvent(time.Now(), &eventPacketReceived{ 294 Header: header, 295 Length: packetSize, 296 PayloadLength: hdr.Length, 297 Frames: fs, 298 }) 299 t.mutex.Unlock() 300 } 301 302 func (t *connectionTracer) ReceivedShortHeaderPacket(hdr *logging.ShortHeader, packetSize logging.ByteCount, frames []logging.Frame) { 303 fs := make([]frame, len(frames)) 304 for i, f := range frames { 305 fs[i] = frame{Frame: f} 306 } 307 header := *transformShortHeader(hdr) 308 t.mutex.Lock() 309 t.recordEvent(time.Now(), &eventPacketReceived{ 310 Header: header, 311 Length: packetSize, 312 PayloadLength: packetSize - wire.ShortHeaderLen(hdr.DestConnectionID, hdr.PacketNumberLen), 313 Frames: fs, 314 }) 315 t.mutex.Unlock() 316 } 317 318 func (t *connectionTracer) ReceivedRetry(hdr *wire.Header) { 319 t.mutex.Lock() 320 t.recordEvent(time.Now(), &eventRetryReceived{ 321 Header: *transformHeader(hdr), 322 }) 323 t.mutex.Unlock() 324 } 325 326 func (t *connectionTracer) ReceivedVersionNegotiationPacket(dest, src logging.ArbitraryLenConnectionID, versions []logging.VersionNumber) { 327 ver := make([]versionNumber, len(versions)) 328 for i, v := range versions { 329 ver[i] = versionNumber(v) 330 } 331 t.mutex.Lock() 332 t.recordEvent(time.Now(), &eventVersionNegotiationReceived{ 333 Header: packetHeaderVersionNegotiation{ 334 SrcConnectionID: src, 335 DestConnectionID: dest, 336 }, 337 SupportedVersions: ver, 338 }) 339 t.mutex.Unlock() 340 } 341 342 func (t *connectionTracer) BufferedPacket(pt logging.PacketType, size protocol.ByteCount) { 343 t.mutex.Lock() 344 t.recordEvent(time.Now(), &eventPacketBuffered{ 345 PacketType: pt, 346 PacketSize: size, 347 }) 348 t.mutex.Unlock() 349 } 350 351 func (t *connectionTracer) DroppedPacket(pt logging.PacketType, size protocol.ByteCount, reason logging.PacketDropReason) { 352 t.mutex.Lock() 353 t.recordEvent(time.Now(), &eventPacketDropped{ 354 PacketType: pt, 355 PacketSize: size, 356 Trigger: packetDropReason(reason), 357 }) 358 t.mutex.Unlock() 359 } 360 361 func (t *connectionTracer) UpdatedMetrics(rttStats *utils.RTTStats, cwnd, bytesInFlight protocol.ByteCount, packetsInFlight int) { 362 m := &metrics{ 363 MinRTT: rttStats.MinRTT(), 364 SmoothedRTT: rttStats.SmoothedRTT(), 365 LatestRTT: rttStats.LatestRTT(), 366 RTTVariance: rttStats.MeanDeviation(), 367 CongestionWindow: cwnd, 368 BytesInFlight: bytesInFlight, 369 PacketsInFlight: packetsInFlight, 370 } 371 t.mutex.Lock() 372 t.recordEvent(time.Now(), &eventMetricsUpdated{ 373 Last: t.lastMetrics, 374 Current: m, 375 }) 376 t.lastMetrics = m 377 t.mutex.Unlock() 378 } 379 380 func (t *connectionTracer) AcknowledgedPacket(protocol.EncryptionLevel, protocol.PacketNumber) {} 381 382 func (t *connectionTracer) LostPacket(encLevel protocol.EncryptionLevel, pn protocol.PacketNumber, lossReason logging.PacketLossReason) { 383 t.mutex.Lock() 384 t.recordEvent(time.Now(), &eventPacketLost{ 385 PacketType: getPacketTypeFromEncryptionLevel(encLevel), 386 PacketNumber: pn, 387 Trigger: packetLossReason(lossReason), 388 }) 389 t.mutex.Unlock() 390 } 391 392 func (t *connectionTracer) UpdatedCongestionState(state logging.CongestionState) { 393 t.mutex.Lock() 394 t.recordEvent(time.Now(), &eventCongestionStateUpdated{state: congestionState(state)}) 395 t.mutex.Unlock() 396 } 397 398 func (t *connectionTracer) UpdatedPTOCount(value uint32) { 399 t.mutex.Lock() 400 t.recordEvent(time.Now(), &eventUpdatedPTO{Value: value}) 401 t.mutex.Unlock() 402 } 403 404 func (t *connectionTracer) UpdatedKeyFromTLS(encLevel protocol.EncryptionLevel, pers protocol.Perspective) { 405 t.mutex.Lock() 406 t.recordEvent(time.Now(), &eventKeyUpdated{ 407 Trigger: keyUpdateTLS, 408 KeyType: encLevelToKeyType(encLevel, pers), 409 }) 410 t.mutex.Unlock() 411 } 412 413 func (t *connectionTracer) UpdatedKey(generation protocol.KeyPhase, remote bool) { 414 trigger := keyUpdateLocal 415 if remote { 416 trigger = keyUpdateRemote 417 } 418 t.mutex.Lock() 419 now := time.Now() 420 t.recordEvent(now, &eventKeyUpdated{ 421 Trigger: trigger, 422 KeyType: keyTypeClient1RTT, 423 Generation: generation, 424 }) 425 t.recordEvent(now, &eventKeyUpdated{ 426 Trigger: trigger, 427 KeyType: keyTypeServer1RTT, 428 Generation: generation, 429 }) 430 t.mutex.Unlock() 431 } 432 433 func (t *connectionTracer) DroppedEncryptionLevel(encLevel protocol.EncryptionLevel) { 434 t.mutex.Lock() 435 now := time.Now() 436 if encLevel == protocol.Encryption0RTT { 437 t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, t.perspective)}) 438 } else { 439 t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveServer)}) 440 t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveClient)}) 441 } 442 t.mutex.Unlock() 443 } 444 445 func (t *connectionTracer) DroppedKey(generation protocol.KeyPhase) { 446 t.mutex.Lock() 447 now := time.Now() 448 t.recordEvent(now, &eventKeyDiscarded{ 449 KeyType: encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveServer), 450 Generation: generation, 451 }) 452 t.recordEvent(now, &eventKeyDiscarded{ 453 KeyType: encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveClient), 454 Generation: generation, 455 }) 456 t.mutex.Unlock() 457 } 458 459 func (t *connectionTracer) SetLossTimer(tt logging.TimerType, encLevel protocol.EncryptionLevel, timeout time.Time) { 460 t.mutex.Lock() 461 now := time.Now() 462 t.recordEvent(now, &eventLossTimerSet{ 463 TimerType: timerType(tt), 464 EncLevel: encLevel, 465 Delta: timeout.Sub(now), 466 }) 467 t.mutex.Unlock() 468 } 469 470 func (t *connectionTracer) LossTimerExpired(tt logging.TimerType, encLevel protocol.EncryptionLevel) { 471 t.mutex.Lock() 472 t.recordEvent(time.Now(), &eventLossTimerExpired{ 473 TimerType: timerType(tt), 474 EncLevel: encLevel, 475 }) 476 t.mutex.Unlock() 477 } 478 479 func (t *connectionTracer) LossTimerCanceled() { 480 t.mutex.Lock() 481 t.recordEvent(time.Now(), &eventLossTimerCanceled{}) 482 t.mutex.Unlock() 483 } 484 485 func (t *connectionTracer) Debug(name, msg string) { 486 t.mutex.Lock() 487 t.recordEvent(time.Now(), &eventGeneric{ 488 name: name, 489 msg: msg, 490 }) 491 t.mutex.Unlock() 492 }