github.com/MerlinKodo/quic-go@v0.39.2/qlog/event.go (about) 1 package qlog 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "time" 8 9 "github.com/MerlinKodo/quic-go" 10 "github.com/MerlinKodo/quic-go/internal/protocol" 11 "github.com/MerlinKodo/quic-go/internal/utils" 12 "github.com/MerlinKodo/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 ECN logging.ECN 162 Trigger string 163 } 164 165 var _ eventDetails = eventPacketSent{} 166 167 func (e eventPacketSent) Category() category { return categoryTransport } 168 func (e eventPacketSent) Name() string { return "packet_sent" } 169 func (e eventPacketSent) IsNil() bool { return false } 170 171 func (e eventPacketSent) MarshalJSONObject(enc *gojay.Encoder) { 172 enc.ObjectKey("header", e.Header) 173 enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength}) 174 enc.ArrayKeyOmitEmpty("frames", e.Frames) 175 enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced) 176 if e.ECN != logging.ECNUnsupported { 177 enc.StringKey("ecn", ecn(e.ECN).String()) 178 } 179 enc.StringKeyOmitEmpty("trigger", e.Trigger) 180 } 181 182 type eventPacketReceived struct { 183 Header gojay.MarshalerJSONObject // either a shortHeader or a packetHeader 184 Length logging.ByteCount 185 PayloadLength logging.ByteCount 186 Frames frames 187 ECN logging.ECN 188 IsCoalesced bool 189 Trigger string 190 } 191 192 var _ eventDetails = eventPacketReceived{} 193 194 func (e eventPacketReceived) Category() category { return categoryTransport } 195 func (e eventPacketReceived) Name() string { return "packet_received" } 196 func (e eventPacketReceived) IsNil() bool { return false } 197 198 func (e eventPacketReceived) MarshalJSONObject(enc *gojay.Encoder) { 199 enc.ObjectKey("header", e.Header) 200 enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength}) 201 enc.ArrayKeyOmitEmpty("frames", e.Frames) 202 enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced) 203 if e.ECN != logging.ECNUnsupported { 204 enc.StringKey("ecn", ecn(e.ECN).String()) 205 } 206 enc.StringKeyOmitEmpty("trigger", e.Trigger) 207 } 208 209 type eventRetryReceived struct { 210 Header packetHeader 211 } 212 213 func (e eventRetryReceived) Category() category { return categoryTransport } 214 func (e eventRetryReceived) Name() string { return "packet_received" } 215 func (e eventRetryReceived) IsNil() bool { return false } 216 217 func (e eventRetryReceived) MarshalJSONObject(enc *gojay.Encoder) { 218 enc.ObjectKey("header", e.Header) 219 } 220 221 type eventVersionNegotiationReceived struct { 222 Header packetHeaderVersionNegotiation 223 SupportedVersions []versionNumber 224 } 225 226 func (e eventVersionNegotiationReceived) Category() category { return categoryTransport } 227 func (e eventVersionNegotiationReceived) Name() string { return "packet_received" } 228 func (e eventVersionNegotiationReceived) IsNil() bool { return false } 229 230 func (e eventVersionNegotiationReceived) MarshalJSONObject(enc *gojay.Encoder) { 231 enc.ObjectKey("header", e.Header) 232 enc.ArrayKey("supported_versions", versions(e.SupportedVersions)) 233 } 234 235 type eventPacketBuffered struct { 236 PacketType logging.PacketType 237 PacketSize protocol.ByteCount 238 } 239 240 func (e eventPacketBuffered) Category() category { return categoryTransport } 241 func (e eventPacketBuffered) Name() string { return "packet_buffered" } 242 func (e eventPacketBuffered) IsNil() bool { return false } 243 244 func (e eventPacketBuffered) MarshalJSONObject(enc *gojay.Encoder) { 245 //nolint:gosimple 246 enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType}) 247 enc.ObjectKey("raw", rawInfo{Length: e.PacketSize}) 248 enc.StringKey("trigger", "keys_unavailable") 249 } 250 251 type eventPacketDropped struct { 252 PacketType logging.PacketType 253 PacketSize protocol.ByteCount 254 Trigger packetDropReason 255 } 256 257 func (e eventPacketDropped) Category() category { return categoryTransport } 258 func (e eventPacketDropped) Name() string { return "packet_dropped" } 259 func (e eventPacketDropped) IsNil() bool { return false } 260 261 func (e eventPacketDropped) MarshalJSONObject(enc *gojay.Encoder) { 262 enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType}) 263 enc.ObjectKey("raw", rawInfo{Length: e.PacketSize}) 264 enc.StringKey("trigger", e.Trigger.String()) 265 } 266 267 type metrics struct { 268 MinRTT time.Duration 269 SmoothedRTT time.Duration 270 LatestRTT time.Duration 271 RTTVariance time.Duration 272 273 CongestionWindow protocol.ByteCount 274 BytesInFlight protocol.ByteCount 275 PacketsInFlight int 276 } 277 278 type eventMetricsUpdated struct { 279 Last *metrics 280 Current *metrics 281 } 282 283 func (e eventMetricsUpdated) Category() category { return categoryRecovery } 284 func (e eventMetricsUpdated) Name() string { return "metrics_updated" } 285 func (e eventMetricsUpdated) IsNil() bool { return false } 286 287 func (e eventMetricsUpdated) MarshalJSONObject(enc *gojay.Encoder) { 288 if e.Last == nil || e.Last.MinRTT != e.Current.MinRTT { 289 enc.FloatKey("min_rtt", milliseconds(e.Current.MinRTT)) 290 } 291 if e.Last == nil || e.Last.SmoothedRTT != e.Current.SmoothedRTT { 292 enc.FloatKey("smoothed_rtt", milliseconds(e.Current.SmoothedRTT)) 293 } 294 if e.Last == nil || e.Last.LatestRTT != e.Current.LatestRTT { 295 enc.FloatKey("latest_rtt", milliseconds(e.Current.LatestRTT)) 296 } 297 if e.Last == nil || e.Last.RTTVariance != e.Current.RTTVariance { 298 enc.FloatKey("rtt_variance", milliseconds(e.Current.RTTVariance)) 299 } 300 301 if e.Last == nil || e.Last.CongestionWindow != e.Current.CongestionWindow { 302 enc.Uint64Key("congestion_window", uint64(e.Current.CongestionWindow)) 303 } 304 if e.Last == nil || e.Last.BytesInFlight != e.Current.BytesInFlight { 305 enc.Uint64Key("bytes_in_flight", uint64(e.Current.BytesInFlight)) 306 } 307 if e.Last == nil || e.Last.PacketsInFlight != e.Current.PacketsInFlight { 308 enc.Uint64KeyOmitEmpty("packets_in_flight", uint64(e.Current.PacketsInFlight)) 309 } 310 } 311 312 type eventUpdatedPTO struct { 313 Value uint32 314 } 315 316 func (e eventUpdatedPTO) Category() category { return categoryRecovery } 317 func (e eventUpdatedPTO) Name() string { return "metrics_updated" } 318 func (e eventUpdatedPTO) IsNil() bool { return false } 319 320 func (e eventUpdatedPTO) MarshalJSONObject(enc *gojay.Encoder) { 321 enc.Uint32Key("pto_count", e.Value) 322 } 323 324 type eventPacketLost struct { 325 PacketType logging.PacketType 326 PacketNumber protocol.PacketNumber 327 Trigger packetLossReason 328 } 329 330 func (e eventPacketLost) Category() category { return categoryRecovery } 331 func (e eventPacketLost) Name() string { return "packet_lost" } 332 func (e eventPacketLost) IsNil() bool { return false } 333 334 func (e eventPacketLost) MarshalJSONObject(enc *gojay.Encoder) { 335 enc.ObjectKey("header", packetHeaderWithTypeAndPacketNumber{ 336 PacketType: e.PacketType, 337 PacketNumber: e.PacketNumber, 338 }) 339 enc.StringKey("trigger", e.Trigger.String()) 340 } 341 342 type eventKeyUpdated struct { 343 Trigger keyUpdateTrigger 344 KeyType keyType 345 Generation protocol.KeyPhase 346 // we don't log the keys here, so we don't need `old` and `new`. 347 } 348 349 func (e eventKeyUpdated) Category() category { return categorySecurity } 350 func (e eventKeyUpdated) Name() string { return "key_updated" } 351 func (e eventKeyUpdated) IsNil() bool { return false } 352 353 func (e eventKeyUpdated) MarshalJSONObject(enc *gojay.Encoder) { 354 enc.StringKey("trigger", e.Trigger.String()) 355 enc.StringKey("key_type", e.KeyType.String()) 356 if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT { 357 enc.Uint64Key("generation", uint64(e.Generation)) 358 } 359 } 360 361 type eventKeyDiscarded struct { 362 KeyType keyType 363 Generation protocol.KeyPhase 364 } 365 366 func (e eventKeyDiscarded) Category() category { return categorySecurity } 367 func (e eventKeyDiscarded) Name() string { return "key_discarded" } 368 func (e eventKeyDiscarded) IsNil() bool { return false } 369 370 func (e eventKeyDiscarded) MarshalJSONObject(enc *gojay.Encoder) { 371 if e.KeyType != keyTypeClient1RTT && e.KeyType != keyTypeServer1RTT { 372 enc.StringKey("trigger", "tls") 373 } 374 enc.StringKey("key_type", e.KeyType.String()) 375 if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT { 376 enc.Uint64Key("generation", uint64(e.Generation)) 377 } 378 } 379 380 type eventTransportParameters struct { 381 Restore bool 382 Owner owner 383 SentBy protocol.Perspective 384 385 OriginalDestinationConnectionID protocol.ConnectionID 386 InitialSourceConnectionID protocol.ConnectionID 387 RetrySourceConnectionID *protocol.ConnectionID 388 389 StatelessResetToken *protocol.StatelessResetToken 390 DisableActiveMigration bool 391 MaxIdleTimeout time.Duration 392 MaxUDPPayloadSize protocol.ByteCount 393 AckDelayExponent uint8 394 MaxAckDelay time.Duration 395 ActiveConnectionIDLimit uint64 396 397 InitialMaxData protocol.ByteCount 398 InitialMaxStreamDataBidiLocal protocol.ByteCount 399 InitialMaxStreamDataBidiRemote protocol.ByteCount 400 InitialMaxStreamDataUni protocol.ByteCount 401 InitialMaxStreamsBidi int64 402 InitialMaxStreamsUni int64 403 404 PreferredAddress *preferredAddress 405 406 MaxDatagramFrameSize protocol.ByteCount 407 } 408 409 func (e eventTransportParameters) Category() category { return categoryTransport } 410 func (e eventTransportParameters) Name() string { 411 if e.Restore { 412 return "parameters_restored" 413 } 414 return "parameters_set" 415 } 416 func (e eventTransportParameters) IsNil() bool { return false } 417 418 func (e eventTransportParameters) MarshalJSONObject(enc *gojay.Encoder) { 419 if !e.Restore { 420 enc.StringKey("owner", e.Owner.String()) 421 if e.SentBy == protocol.PerspectiveServer { 422 enc.StringKey("original_destination_connection_id", e.OriginalDestinationConnectionID.String()) 423 if e.StatelessResetToken != nil { 424 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", e.StatelessResetToken[:])) 425 } 426 if e.RetrySourceConnectionID != nil { 427 enc.StringKey("retry_source_connection_id", (*e.RetrySourceConnectionID).String()) 428 } 429 } 430 enc.StringKey("initial_source_connection_id", e.InitialSourceConnectionID.String()) 431 } 432 enc.BoolKey("disable_active_migration", e.DisableActiveMigration) 433 enc.FloatKeyOmitEmpty("max_idle_timeout", milliseconds(e.MaxIdleTimeout)) 434 enc.Int64KeyNullEmpty("max_udp_payload_size", int64(e.MaxUDPPayloadSize)) 435 enc.Uint8KeyOmitEmpty("ack_delay_exponent", e.AckDelayExponent) 436 enc.FloatKeyOmitEmpty("max_ack_delay", milliseconds(e.MaxAckDelay)) 437 enc.Uint64KeyOmitEmpty("active_connection_id_limit", e.ActiveConnectionIDLimit) 438 439 enc.Int64KeyOmitEmpty("initial_max_data", int64(e.InitialMaxData)) 440 enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_local", int64(e.InitialMaxStreamDataBidiLocal)) 441 enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_remote", int64(e.InitialMaxStreamDataBidiRemote)) 442 enc.Int64KeyOmitEmpty("initial_max_stream_data_uni", int64(e.InitialMaxStreamDataUni)) 443 enc.Int64KeyOmitEmpty("initial_max_streams_bidi", e.InitialMaxStreamsBidi) 444 enc.Int64KeyOmitEmpty("initial_max_streams_uni", e.InitialMaxStreamsUni) 445 446 if e.PreferredAddress != nil { 447 enc.ObjectKey("preferred_address", e.PreferredAddress) 448 } 449 if e.MaxDatagramFrameSize != protocol.InvalidByteCount { 450 enc.Int64Key("max_datagram_frame_size", int64(e.MaxDatagramFrameSize)) 451 } 452 } 453 454 type preferredAddress struct { 455 IPv4, IPv6 net.IP 456 PortV4, PortV6 uint16 457 ConnectionID protocol.ConnectionID 458 StatelessResetToken protocol.StatelessResetToken 459 } 460 461 var _ gojay.MarshalerJSONObject = &preferredAddress{} 462 463 func (a preferredAddress) IsNil() bool { return false } 464 func (a preferredAddress) MarshalJSONObject(enc *gojay.Encoder) { 465 enc.StringKey("ip_v4", a.IPv4.String()) 466 enc.Uint16Key("port_v4", a.PortV4) 467 enc.StringKey("ip_v6", a.IPv6.String()) 468 enc.Uint16Key("port_v6", a.PortV6) 469 enc.StringKey("connection_id", a.ConnectionID.String()) 470 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", a.StatelessResetToken)) 471 } 472 473 type eventLossTimerSet struct { 474 TimerType timerType 475 EncLevel protocol.EncryptionLevel 476 Delta time.Duration 477 } 478 479 func (e eventLossTimerSet) Category() category { return categoryRecovery } 480 func (e eventLossTimerSet) Name() string { return "loss_timer_updated" } 481 func (e eventLossTimerSet) IsNil() bool { return false } 482 483 func (e eventLossTimerSet) MarshalJSONObject(enc *gojay.Encoder) { 484 enc.StringKey("event_type", "set") 485 enc.StringKey("timer_type", e.TimerType.String()) 486 enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel)) 487 enc.Float64Key("delta", milliseconds(e.Delta)) 488 } 489 490 type eventLossTimerExpired struct { 491 TimerType timerType 492 EncLevel protocol.EncryptionLevel 493 } 494 495 func (e eventLossTimerExpired) Category() category { return categoryRecovery } 496 func (e eventLossTimerExpired) Name() string { return "loss_timer_updated" } 497 func (e eventLossTimerExpired) IsNil() bool { return false } 498 499 func (e eventLossTimerExpired) MarshalJSONObject(enc *gojay.Encoder) { 500 enc.StringKey("event_type", "expired") 501 enc.StringKey("timer_type", e.TimerType.String()) 502 enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel)) 503 } 504 505 type eventLossTimerCanceled struct{} 506 507 func (e eventLossTimerCanceled) Category() category { return categoryRecovery } 508 func (e eventLossTimerCanceled) Name() string { return "loss_timer_updated" } 509 func (e eventLossTimerCanceled) IsNil() bool { return false } 510 511 func (e eventLossTimerCanceled) MarshalJSONObject(enc *gojay.Encoder) { 512 enc.StringKey("event_type", "cancelled") 513 } 514 515 type eventCongestionStateUpdated struct { 516 state congestionState 517 } 518 519 func (e eventCongestionStateUpdated) Category() category { return categoryRecovery } 520 func (e eventCongestionStateUpdated) Name() string { return "congestion_state_updated" } 521 func (e eventCongestionStateUpdated) IsNil() bool { return false } 522 523 func (e eventCongestionStateUpdated) MarshalJSONObject(enc *gojay.Encoder) { 524 enc.StringKey("new", e.state.String()) 525 } 526 527 type eventECNStateUpdated struct { 528 state logging.ECNState 529 trigger logging.ECNStateTrigger 530 } 531 532 func (e eventECNStateUpdated) Category() category { return categoryRecovery } 533 func (e eventECNStateUpdated) Name() string { return "ecn_state_updated" } 534 func (e eventECNStateUpdated) IsNil() bool { return false } 535 536 func (e eventECNStateUpdated) MarshalJSONObject(enc *gojay.Encoder) { 537 enc.StringKey("new", ecnState(e.state).String()) 538 enc.StringKeyOmitEmpty("trigger", ecnStateTrigger(e.trigger).String()) 539 } 540 541 type eventGeneric struct { 542 name string 543 msg string 544 } 545 546 func (e eventGeneric) Category() category { return categoryTransport } 547 func (e eventGeneric) Name() string { return e.name } 548 func (e eventGeneric) IsNil() bool { return false } 549 550 func (e eventGeneric) MarshalJSONObject(enc *gojay.Encoder) { 551 enc.StringKey("details", e.msg) 552 }