github.com/mikelsr/quic-go@v0.36.1-0.20230701132136-1d9415b66898/qlog/event.go (about) 1 package qlog 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "time" 8 9 "github.com/mikelsr/quic-go" 10 "github.com/mikelsr/quic-go/internal/protocol" 11 "github.com/mikelsr/quic-go/internal/utils" 12 "github.com/mikelsr/quic-go/logging" 13 14 "github.com/francoispqt/gojay" 15 ) 16 17 func milliseconds(dur time.Duration) float64 { return float64(dur.Nanoseconds()) / 1e6 } 18 19 type eventDetails interface { 20 Category() category 21 Name() string 22 gojay.MarshalerJSONObject 23 } 24 25 type event struct { 26 RelativeTime time.Duration 27 eventDetails 28 } 29 30 var _ gojay.MarshalerJSONObject = event{} 31 32 func (e event) IsNil() bool { return false } 33 func (e event) MarshalJSONObject(enc *gojay.Encoder) { 34 enc.Float64Key("time", milliseconds(e.RelativeTime)) 35 enc.StringKey("name", e.Category().String()+":"+e.Name()) 36 enc.ObjectKey("data", e.eventDetails) 37 } 38 39 type versions []versionNumber 40 41 func (v versions) IsNil() bool { return false } 42 func (v versions) MarshalJSONArray(enc *gojay.Encoder) { 43 for _, e := range v { 44 enc.AddString(e.String()) 45 } 46 } 47 48 type rawInfo struct { 49 Length logging.ByteCount // full packet length, including header and AEAD authentication tag 50 PayloadLength logging.ByteCount // length of the packet payload, excluding AEAD tag 51 } 52 53 func (i rawInfo) IsNil() bool { return false } 54 func (i rawInfo) MarshalJSONObject(enc *gojay.Encoder) { 55 enc.Uint64Key("length", uint64(i.Length)) 56 enc.Uint64KeyOmitEmpty("payload_length", uint64(i.PayloadLength)) 57 } 58 59 type eventConnectionStarted struct { 60 SrcAddr *net.UDPAddr 61 DestAddr *net.UDPAddr 62 63 SrcConnectionID protocol.ConnectionID 64 DestConnectionID protocol.ConnectionID 65 } 66 67 var _ eventDetails = &eventConnectionStarted{} 68 69 func (e eventConnectionStarted) Category() category { return categoryTransport } 70 func (e eventConnectionStarted) Name() string { return "connection_started" } 71 func (e eventConnectionStarted) IsNil() bool { return false } 72 73 func (e eventConnectionStarted) MarshalJSONObject(enc *gojay.Encoder) { 74 if utils.IsIPv4(e.SrcAddr.IP) { 75 enc.StringKey("ip_version", "ipv4") 76 } else { 77 enc.StringKey("ip_version", "ipv6") 78 } 79 enc.StringKey("src_ip", e.SrcAddr.IP.String()) 80 enc.IntKey("src_port", e.SrcAddr.Port) 81 enc.StringKey("dst_ip", e.DestAddr.IP.String()) 82 enc.IntKey("dst_port", e.DestAddr.Port) 83 enc.StringKey("src_cid", e.SrcConnectionID.String()) 84 enc.StringKey("dst_cid", e.DestConnectionID.String()) 85 } 86 87 type eventVersionNegotiated struct { 88 clientVersions, serverVersions []versionNumber 89 chosenVersion versionNumber 90 } 91 92 func (e eventVersionNegotiated) Category() category { return categoryTransport } 93 func (e eventVersionNegotiated) Name() string { return "version_information" } 94 func (e eventVersionNegotiated) IsNil() bool { return false } 95 96 func (e eventVersionNegotiated) MarshalJSONObject(enc *gojay.Encoder) { 97 if len(e.clientVersions) > 0 { 98 enc.ArrayKey("client_versions", versions(e.clientVersions)) 99 } 100 if len(e.serverVersions) > 0 { 101 enc.ArrayKey("server_versions", versions(e.serverVersions)) 102 } 103 enc.StringKey("chosen_version", e.chosenVersion.String()) 104 } 105 106 type eventConnectionClosed struct { 107 e error 108 } 109 110 func (e eventConnectionClosed) Category() category { return categoryTransport } 111 func (e eventConnectionClosed) Name() string { return "connection_closed" } 112 func (e eventConnectionClosed) IsNil() bool { return false } 113 114 func (e eventConnectionClosed) MarshalJSONObject(enc *gojay.Encoder) { 115 var ( 116 statelessResetErr *quic.StatelessResetError 117 handshakeTimeoutErr *quic.HandshakeTimeoutError 118 idleTimeoutErr *quic.IdleTimeoutError 119 applicationErr *quic.ApplicationError 120 transportErr *quic.TransportError 121 versionNegotiationErr *quic.VersionNegotiationError 122 ) 123 switch { 124 case errors.As(e.e, &statelessResetErr): 125 enc.StringKey("owner", ownerRemote.String()) 126 enc.StringKey("trigger", "stateless_reset") 127 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", statelessResetErr.Token)) 128 case errors.As(e.e, &handshakeTimeoutErr): 129 enc.StringKey("owner", ownerLocal.String()) 130 enc.StringKey("trigger", "handshake_timeout") 131 case errors.As(e.e, &idleTimeoutErr): 132 enc.StringKey("owner", ownerLocal.String()) 133 enc.StringKey("trigger", "idle_timeout") 134 case errors.As(e.e, &applicationErr): 135 owner := ownerLocal 136 if applicationErr.Remote { 137 owner = ownerRemote 138 } 139 enc.StringKey("owner", owner.String()) 140 enc.Uint64Key("application_code", uint64(applicationErr.ErrorCode)) 141 enc.StringKey("reason", applicationErr.ErrorMessage) 142 case errors.As(e.e, &transportErr): 143 owner := ownerLocal 144 if transportErr.Remote { 145 owner = ownerRemote 146 } 147 enc.StringKey("owner", owner.String()) 148 enc.StringKey("connection_code", transportError(transportErr.ErrorCode).String()) 149 enc.StringKey("reason", transportErr.ErrorMessage) 150 case errors.As(e.e, &versionNegotiationErr): 151 enc.StringKey("trigger", "version_mismatch") 152 } 153 } 154 155 type eventPacketSent struct { 156 Header gojay.MarshalerJSONObject // either a shortHeader or a packetHeader 157 Length logging.ByteCount 158 PayloadLength logging.ByteCount 159 Frames frames 160 IsCoalesced bool 161 Trigger string 162 } 163 164 var _ eventDetails = eventPacketSent{} 165 166 func (e eventPacketSent) Category() category { return categoryTransport } 167 func (e eventPacketSent) Name() string { return "packet_sent" } 168 func (e eventPacketSent) IsNil() bool { return false } 169 170 func (e eventPacketSent) MarshalJSONObject(enc *gojay.Encoder) { 171 enc.ObjectKey("header", e.Header) 172 enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength}) 173 enc.ArrayKeyOmitEmpty("frames", e.Frames) 174 enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced) 175 enc.StringKeyOmitEmpty("trigger", e.Trigger) 176 } 177 178 type eventPacketReceived struct { 179 Header gojay.MarshalerJSONObject // either a shortHeader or a packetHeader 180 Length logging.ByteCount 181 PayloadLength logging.ByteCount 182 Frames frames 183 IsCoalesced bool 184 Trigger string 185 } 186 187 var _ eventDetails = eventPacketReceived{} 188 189 func (e eventPacketReceived) Category() category { return categoryTransport } 190 func (e eventPacketReceived) Name() string { return "packet_received" } 191 func (e eventPacketReceived) IsNil() bool { return false } 192 193 func (e eventPacketReceived) MarshalJSONObject(enc *gojay.Encoder) { 194 enc.ObjectKey("header", e.Header) 195 enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength}) 196 enc.ArrayKeyOmitEmpty("frames", e.Frames) 197 enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced) 198 enc.StringKeyOmitEmpty("trigger", e.Trigger) 199 } 200 201 type eventRetryReceived struct { 202 Header packetHeader 203 } 204 205 func (e eventRetryReceived) Category() category { return categoryTransport } 206 func (e eventRetryReceived) Name() string { return "packet_received" } 207 func (e eventRetryReceived) IsNil() bool { return false } 208 209 func (e eventRetryReceived) MarshalJSONObject(enc *gojay.Encoder) { 210 enc.ObjectKey("header", e.Header) 211 } 212 213 type eventVersionNegotiationReceived struct { 214 Header packetHeaderVersionNegotiation 215 SupportedVersions []versionNumber 216 } 217 218 func (e eventVersionNegotiationReceived) Category() category { return categoryTransport } 219 func (e eventVersionNegotiationReceived) Name() string { return "packet_received" } 220 func (e eventVersionNegotiationReceived) IsNil() bool { return false } 221 222 func (e eventVersionNegotiationReceived) MarshalJSONObject(enc *gojay.Encoder) { 223 enc.ObjectKey("header", e.Header) 224 enc.ArrayKey("supported_versions", versions(e.SupportedVersions)) 225 } 226 227 type eventPacketBuffered struct { 228 PacketType logging.PacketType 229 PacketSize protocol.ByteCount 230 } 231 232 func (e eventPacketBuffered) Category() category { return categoryTransport } 233 func (e eventPacketBuffered) Name() string { return "packet_buffered" } 234 func (e eventPacketBuffered) IsNil() bool { return false } 235 236 func (e eventPacketBuffered) MarshalJSONObject(enc *gojay.Encoder) { 237 //nolint:gosimple 238 enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType}) 239 enc.ObjectKey("raw", rawInfo{Length: e.PacketSize}) 240 enc.StringKey("trigger", "keys_unavailable") 241 } 242 243 type eventPacketDropped struct { 244 PacketType logging.PacketType 245 PacketSize protocol.ByteCount 246 Trigger packetDropReason 247 } 248 249 func (e eventPacketDropped) Category() category { return categoryTransport } 250 func (e eventPacketDropped) Name() string { return "packet_dropped" } 251 func (e eventPacketDropped) IsNil() bool { return false } 252 253 func (e eventPacketDropped) MarshalJSONObject(enc *gojay.Encoder) { 254 enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType}) 255 enc.ObjectKey("raw", rawInfo{Length: e.PacketSize}) 256 enc.StringKey("trigger", e.Trigger.String()) 257 } 258 259 type metrics struct { 260 MinRTT time.Duration 261 SmoothedRTT time.Duration 262 LatestRTT time.Duration 263 RTTVariance time.Duration 264 265 CongestionWindow protocol.ByteCount 266 BytesInFlight protocol.ByteCount 267 PacketsInFlight int 268 } 269 270 type eventMetricsUpdated struct { 271 Last *metrics 272 Current *metrics 273 } 274 275 func (e eventMetricsUpdated) Category() category { return categoryRecovery } 276 func (e eventMetricsUpdated) Name() string { return "metrics_updated" } 277 func (e eventMetricsUpdated) IsNil() bool { return false } 278 279 func (e eventMetricsUpdated) MarshalJSONObject(enc *gojay.Encoder) { 280 if e.Last == nil || e.Last.MinRTT != e.Current.MinRTT { 281 enc.FloatKey("min_rtt", milliseconds(e.Current.MinRTT)) 282 } 283 if e.Last == nil || e.Last.SmoothedRTT != e.Current.SmoothedRTT { 284 enc.FloatKey("smoothed_rtt", milliseconds(e.Current.SmoothedRTT)) 285 } 286 if e.Last == nil || e.Last.LatestRTT != e.Current.LatestRTT { 287 enc.FloatKey("latest_rtt", milliseconds(e.Current.LatestRTT)) 288 } 289 if e.Last == nil || e.Last.RTTVariance != e.Current.RTTVariance { 290 enc.FloatKey("rtt_variance", milliseconds(e.Current.RTTVariance)) 291 } 292 293 if e.Last == nil || e.Last.CongestionWindow != e.Current.CongestionWindow { 294 enc.Uint64Key("congestion_window", uint64(e.Current.CongestionWindow)) 295 } 296 if e.Last == nil || e.Last.BytesInFlight != e.Current.BytesInFlight { 297 enc.Uint64Key("bytes_in_flight", uint64(e.Current.BytesInFlight)) 298 } 299 if e.Last == nil || e.Last.PacketsInFlight != e.Current.PacketsInFlight { 300 enc.Uint64KeyOmitEmpty("packets_in_flight", uint64(e.Current.PacketsInFlight)) 301 } 302 } 303 304 type eventUpdatedPTO struct { 305 Value uint32 306 } 307 308 func (e eventUpdatedPTO) Category() category { return categoryRecovery } 309 func (e eventUpdatedPTO) Name() string { return "metrics_updated" } 310 func (e eventUpdatedPTO) IsNil() bool { return false } 311 312 func (e eventUpdatedPTO) MarshalJSONObject(enc *gojay.Encoder) { 313 enc.Uint32Key("pto_count", e.Value) 314 } 315 316 type eventPacketLost struct { 317 PacketType logging.PacketType 318 PacketNumber protocol.PacketNumber 319 Trigger packetLossReason 320 } 321 322 func (e eventPacketLost) Category() category { return categoryRecovery } 323 func (e eventPacketLost) Name() string { return "packet_lost" } 324 func (e eventPacketLost) IsNil() bool { return false } 325 326 func (e eventPacketLost) MarshalJSONObject(enc *gojay.Encoder) { 327 enc.ObjectKey("header", packetHeaderWithTypeAndPacketNumber{ 328 PacketType: e.PacketType, 329 PacketNumber: e.PacketNumber, 330 }) 331 enc.StringKey("trigger", e.Trigger.String()) 332 } 333 334 type eventKeyUpdated struct { 335 Trigger keyUpdateTrigger 336 KeyType keyType 337 Generation protocol.KeyPhase 338 // we don't log the keys here, so we don't need `old` and `new`. 339 } 340 341 func (e eventKeyUpdated) Category() category { return categorySecurity } 342 func (e eventKeyUpdated) Name() string { return "key_updated" } 343 func (e eventKeyUpdated) IsNil() bool { return false } 344 345 func (e eventKeyUpdated) MarshalJSONObject(enc *gojay.Encoder) { 346 enc.StringKey("trigger", e.Trigger.String()) 347 enc.StringKey("key_type", e.KeyType.String()) 348 if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT { 349 enc.Uint64Key("generation", uint64(e.Generation)) 350 } 351 } 352 353 type eventKeyDiscarded struct { 354 KeyType keyType 355 Generation protocol.KeyPhase 356 } 357 358 func (e eventKeyDiscarded) Category() category { return categorySecurity } 359 func (e eventKeyDiscarded) Name() string { return "key_discarded" } 360 func (e eventKeyDiscarded) IsNil() bool { return false } 361 362 func (e eventKeyDiscarded) MarshalJSONObject(enc *gojay.Encoder) { 363 if e.KeyType != keyTypeClient1RTT && e.KeyType != keyTypeServer1RTT { 364 enc.StringKey("trigger", "tls") 365 } 366 enc.StringKey("key_type", e.KeyType.String()) 367 if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT { 368 enc.Uint64Key("generation", uint64(e.Generation)) 369 } 370 } 371 372 type eventTransportParameters struct { 373 Restore bool 374 Owner owner 375 SentBy protocol.Perspective 376 377 OriginalDestinationConnectionID protocol.ConnectionID 378 InitialSourceConnectionID protocol.ConnectionID 379 RetrySourceConnectionID *protocol.ConnectionID 380 381 StatelessResetToken *protocol.StatelessResetToken 382 DisableActiveMigration bool 383 MaxIdleTimeout time.Duration 384 MaxUDPPayloadSize protocol.ByteCount 385 AckDelayExponent uint8 386 MaxAckDelay time.Duration 387 ActiveConnectionIDLimit uint64 388 389 InitialMaxData protocol.ByteCount 390 InitialMaxStreamDataBidiLocal protocol.ByteCount 391 InitialMaxStreamDataBidiRemote protocol.ByteCount 392 InitialMaxStreamDataUni protocol.ByteCount 393 InitialMaxStreamsBidi int64 394 InitialMaxStreamsUni int64 395 396 PreferredAddress *preferredAddress 397 398 MaxDatagramFrameSize protocol.ByteCount 399 } 400 401 func (e eventTransportParameters) Category() category { return categoryTransport } 402 func (e eventTransportParameters) Name() string { 403 if e.Restore { 404 return "parameters_restored" 405 } 406 return "parameters_set" 407 } 408 func (e eventTransportParameters) IsNil() bool { return false } 409 410 func (e eventTransportParameters) MarshalJSONObject(enc *gojay.Encoder) { 411 if !e.Restore { 412 enc.StringKey("owner", e.Owner.String()) 413 if e.SentBy == protocol.PerspectiveServer { 414 enc.StringKey("original_destination_connection_id", e.OriginalDestinationConnectionID.String()) 415 if e.StatelessResetToken != nil { 416 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", e.StatelessResetToken[:])) 417 } 418 if e.RetrySourceConnectionID != nil { 419 enc.StringKey("retry_source_connection_id", (*e.RetrySourceConnectionID).String()) 420 } 421 } 422 enc.StringKey("initial_source_connection_id", e.InitialSourceConnectionID.String()) 423 } 424 enc.BoolKey("disable_active_migration", e.DisableActiveMigration) 425 enc.FloatKeyOmitEmpty("max_idle_timeout", milliseconds(e.MaxIdleTimeout)) 426 enc.Int64KeyNullEmpty("max_udp_payload_size", int64(e.MaxUDPPayloadSize)) 427 enc.Uint8KeyOmitEmpty("ack_delay_exponent", e.AckDelayExponent) 428 enc.FloatKeyOmitEmpty("max_ack_delay", milliseconds(e.MaxAckDelay)) 429 enc.Uint64KeyOmitEmpty("active_connection_id_limit", e.ActiveConnectionIDLimit) 430 431 enc.Int64KeyOmitEmpty("initial_max_data", int64(e.InitialMaxData)) 432 enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_local", int64(e.InitialMaxStreamDataBidiLocal)) 433 enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_remote", int64(e.InitialMaxStreamDataBidiRemote)) 434 enc.Int64KeyOmitEmpty("initial_max_stream_data_uni", int64(e.InitialMaxStreamDataUni)) 435 enc.Int64KeyOmitEmpty("initial_max_streams_bidi", e.InitialMaxStreamsBidi) 436 enc.Int64KeyOmitEmpty("initial_max_streams_uni", e.InitialMaxStreamsUni) 437 438 if e.PreferredAddress != nil { 439 enc.ObjectKey("preferred_address", e.PreferredAddress) 440 } 441 if e.MaxDatagramFrameSize != protocol.InvalidByteCount { 442 enc.Int64Key("max_datagram_frame_size", int64(e.MaxDatagramFrameSize)) 443 } 444 } 445 446 type preferredAddress struct { 447 IPv4, IPv6 net.IP 448 PortV4, PortV6 uint16 449 ConnectionID protocol.ConnectionID 450 StatelessResetToken protocol.StatelessResetToken 451 } 452 453 var _ gojay.MarshalerJSONObject = &preferredAddress{} 454 455 func (a preferredAddress) IsNil() bool { return false } 456 func (a preferredAddress) MarshalJSONObject(enc *gojay.Encoder) { 457 enc.StringKey("ip_v4", a.IPv4.String()) 458 enc.Uint16Key("port_v4", a.PortV4) 459 enc.StringKey("ip_v6", a.IPv6.String()) 460 enc.Uint16Key("port_v6", a.PortV6) 461 enc.StringKey("connection_id", a.ConnectionID.String()) 462 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", a.StatelessResetToken)) 463 } 464 465 type eventLossTimerSet struct { 466 TimerType timerType 467 EncLevel protocol.EncryptionLevel 468 Delta time.Duration 469 } 470 471 func (e eventLossTimerSet) Category() category { return categoryRecovery } 472 func (e eventLossTimerSet) Name() string { return "loss_timer_updated" } 473 func (e eventLossTimerSet) IsNil() bool { return false } 474 475 func (e eventLossTimerSet) MarshalJSONObject(enc *gojay.Encoder) { 476 enc.StringKey("event_type", "set") 477 enc.StringKey("timer_type", e.TimerType.String()) 478 enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel)) 479 enc.Float64Key("delta", milliseconds(e.Delta)) 480 } 481 482 type eventLossTimerExpired struct { 483 TimerType timerType 484 EncLevel protocol.EncryptionLevel 485 } 486 487 func (e eventLossTimerExpired) Category() category { return categoryRecovery } 488 func (e eventLossTimerExpired) Name() string { return "loss_timer_updated" } 489 func (e eventLossTimerExpired) IsNil() bool { return false } 490 491 func (e eventLossTimerExpired) MarshalJSONObject(enc *gojay.Encoder) { 492 enc.StringKey("event_type", "expired") 493 enc.StringKey("timer_type", e.TimerType.String()) 494 enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel)) 495 } 496 497 type eventLossTimerCanceled struct{} 498 499 func (e eventLossTimerCanceled) Category() category { return categoryRecovery } 500 func (e eventLossTimerCanceled) Name() string { return "loss_timer_updated" } 501 func (e eventLossTimerCanceled) IsNil() bool { return false } 502 503 func (e eventLossTimerCanceled) MarshalJSONObject(enc *gojay.Encoder) { 504 enc.StringKey("event_type", "cancelled") 505 } 506 507 type eventCongestionStateUpdated struct { 508 state congestionState 509 } 510 511 func (e eventCongestionStateUpdated) Category() category { return categoryRecovery } 512 func (e eventCongestionStateUpdated) Name() string { return "congestion_state_updated" } 513 func (e eventCongestionStateUpdated) IsNil() bool { return false } 514 515 func (e eventCongestionStateUpdated) MarshalJSONObject(enc *gojay.Encoder) { 516 enc.StringKey("new", e.state.String()) 517 } 518 519 type eventGeneric struct { 520 name string 521 msg string 522 } 523 524 func (e eventGeneric) Category() category { return categoryTransport } 525 func (e eventGeneric) Name() string { return e.name } 526 func (e eventGeneric) IsNil() bool { return false } 527 528 func (e eventGeneric) MarshalJSONObject(enc *gojay.Encoder) { 529 enc.StringKey("details", e.msg) 530 }