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