github.com/sagernet/quic-go@v0.43.1-beta.1/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/francoispqt/gojay" 11 "github.com/sagernet/quic-go" 12 "github.com/sagernet/quic-go/internal/protocol" 13 "github.com/sagernet/quic-go/internal/utils" 14 "github.com/sagernet/quic-go/logging" 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 eventVersionNegotiationSent struct { 236 Header packetHeaderVersionNegotiation 237 SupportedVersions []versionNumber 238 } 239 240 func (e eventVersionNegotiationSent) Category() category { return categoryTransport } 241 func (e eventVersionNegotiationSent) Name() string { return "packet_sent" } 242 func (e eventVersionNegotiationSent) IsNil() bool { return false } 243 244 func (e eventVersionNegotiationSent) MarshalJSONObject(enc *gojay.Encoder) { 245 enc.ObjectKey("header", e.Header) 246 enc.ArrayKey("supported_versions", versions(e.SupportedVersions)) 247 } 248 249 type eventPacketBuffered struct { 250 PacketType logging.PacketType 251 PacketSize protocol.ByteCount 252 } 253 254 func (e eventPacketBuffered) Category() category { return categoryTransport } 255 func (e eventPacketBuffered) Name() string { return "packet_buffered" } 256 func (e eventPacketBuffered) IsNil() bool { return false } 257 258 func (e eventPacketBuffered) MarshalJSONObject(enc *gojay.Encoder) { 259 //nolint:gosimple 260 enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType, PacketNumber: protocol.InvalidPacketNumber}) 261 enc.ObjectKey("raw", rawInfo{Length: e.PacketSize}) 262 enc.StringKey("trigger", "keys_unavailable") 263 } 264 265 type eventPacketDropped struct { 266 PacketType logging.PacketType 267 PacketSize protocol.ByteCount 268 PacketNumber logging.PacketNumber 269 Trigger packetDropReason 270 } 271 272 func (e eventPacketDropped) Category() category { return categoryTransport } 273 func (e eventPacketDropped) Name() string { return "packet_dropped" } 274 func (e eventPacketDropped) IsNil() bool { return false } 275 276 func (e eventPacketDropped) MarshalJSONObject(enc *gojay.Encoder) { 277 enc.ObjectKey("header", packetHeaderWithType{ 278 PacketType: e.PacketType, 279 PacketNumber: e.PacketNumber, 280 }) 281 enc.ObjectKey("raw", rawInfo{Length: e.PacketSize}) 282 enc.StringKey("trigger", e.Trigger.String()) 283 } 284 285 type metrics struct { 286 MinRTT time.Duration 287 SmoothedRTT time.Duration 288 LatestRTT time.Duration 289 RTTVariance time.Duration 290 291 CongestionWindow protocol.ByteCount 292 BytesInFlight protocol.ByteCount 293 PacketsInFlight int 294 } 295 296 type eventMetricsUpdated struct { 297 Last *metrics 298 Current *metrics 299 } 300 301 func (e eventMetricsUpdated) Category() category { return categoryRecovery } 302 func (e eventMetricsUpdated) Name() string { return "metrics_updated" } 303 func (e eventMetricsUpdated) IsNil() bool { return false } 304 305 func (e eventMetricsUpdated) MarshalJSONObject(enc *gojay.Encoder) { 306 if e.Last == nil || e.Last.MinRTT != e.Current.MinRTT { 307 enc.FloatKey("min_rtt", milliseconds(e.Current.MinRTT)) 308 } 309 if e.Last == nil || e.Last.SmoothedRTT != e.Current.SmoothedRTT { 310 enc.FloatKey("smoothed_rtt", milliseconds(e.Current.SmoothedRTT)) 311 } 312 if e.Last == nil || e.Last.LatestRTT != e.Current.LatestRTT { 313 enc.FloatKey("latest_rtt", milliseconds(e.Current.LatestRTT)) 314 } 315 if e.Last == nil || e.Last.RTTVariance != e.Current.RTTVariance { 316 enc.FloatKey("rtt_variance", milliseconds(e.Current.RTTVariance)) 317 } 318 319 if e.Last == nil || e.Last.CongestionWindow != e.Current.CongestionWindow { 320 enc.Uint64Key("congestion_window", uint64(e.Current.CongestionWindow)) 321 } 322 if e.Last == nil || e.Last.BytesInFlight != e.Current.BytesInFlight { 323 enc.Uint64Key("bytes_in_flight", uint64(e.Current.BytesInFlight)) 324 } 325 if e.Last == nil || e.Last.PacketsInFlight != e.Current.PacketsInFlight { 326 enc.Uint64KeyOmitEmpty("packets_in_flight", uint64(e.Current.PacketsInFlight)) 327 } 328 } 329 330 type eventUpdatedPTO struct { 331 Value uint32 332 } 333 334 func (e eventUpdatedPTO) Category() category { return categoryRecovery } 335 func (e eventUpdatedPTO) Name() string { return "metrics_updated" } 336 func (e eventUpdatedPTO) IsNil() bool { return false } 337 338 func (e eventUpdatedPTO) MarshalJSONObject(enc *gojay.Encoder) { 339 enc.Uint32Key("pto_count", e.Value) 340 } 341 342 type eventPacketLost struct { 343 PacketType logging.PacketType 344 PacketNumber protocol.PacketNumber 345 Trigger packetLossReason 346 } 347 348 func (e eventPacketLost) Category() category { return categoryRecovery } 349 func (e eventPacketLost) Name() string { return "packet_lost" } 350 func (e eventPacketLost) IsNil() bool { return false } 351 352 func (e eventPacketLost) MarshalJSONObject(enc *gojay.Encoder) { 353 enc.ObjectKey("header", packetHeaderWithTypeAndPacketNumber{ 354 PacketType: e.PacketType, 355 PacketNumber: e.PacketNumber, 356 }) 357 enc.StringKey("trigger", e.Trigger.String()) 358 } 359 360 type eventKeyUpdated struct { 361 Trigger keyUpdateTrigger 362 KeyType keyType 363 KeyPhase protocol.KeyPhase 364 // we don't log the keys here, so we don't need `old` and `new`. 365 } 366 367 func (e eventKeyUpdated) Category() category { return categorySecurity } 368 func (e eventKeyUpdated) Name() string { return "key_updated" } 369 func (e eventKeyUpdated) IsNil() bool { return false } 370 371 func (e eventKeyUpdated) MarshalJSONObject(enc *gojay.Encoder) { 372 enc.StringKey("trigger", e.Trigger.String()) 373 enc.StringKey("key_type", e.KeyType.String()) 374 if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT { 375 enc.Uint64Key("key_phase", uint64(e.KeyPhase)) 376 } 377 } 378 379 type eventKeyDiscarded struct { 380 KeyType keyType 381 KeyPhase protocol.KeyPhase 382 } 383 384 func (e eventKeyDiscarded) Category() category { return categorySecurity } 385 func (e eventKeyDiscarded) Name() string { return "key_discarded" } 386 func (e eventKeyDiscarded) IsNil() bool { return false } 387 388 func (e eventKeyDiscarded) MarshalJSONObject(enc *gojay.Encoder) { 389 if e.KeyType != keyTypeClient1RTT && e.KeyType != keyTypeServer1RTT { 390 enc.StringKey("trigger", "tls") 391 } 392 enc.StringKey("key_type", e.KeyType.String()) 393 if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT { 394 enc.Uint64Key("key_phase", uint64(e.KeyPhase)) 395 } 396 } 397 398 type eventTransportParameters struct { 399 Restore bool 400 Owner owner 401 SentBy protocol.Perspective 402 403 OriginalDestinationConnectionID protocol.ConnectionID 404 InitialSourceConnectionID protocol.ConnectionID 405 RetrySourceConnectionID *protocol.ConnectionID 406 407 StatelessResetToken *protocol.StatelessResetToken 408 DisableActiveMigration bool 409 MaxIdleTimeout time.Duration 410 MaxUDPPayloadSize protocol.ByteCount 411 AckDelayExponent uint8 412 MaxAckDelay time.Duration 413 ActiveConnectionIDLimit uint64 414 415 InitialMaxData protocol.ByteCount 416 InitialMaxStreamDataBidiLocal protocol.ByteCount 417 InitialMaxStreamDataBidiRemote protocol.ByteCount 418 InitialMaxStreamDataUni protocol.ByteCount 419 InitialMaxStreamsBidi int64 420 InitialMaxStreamsUni int64 421 422 PreferredAddress *preferredAddress 423 424 MaxDatagramFrameSize protocol.ByteCount 425 } 426 427 func (e eventTransportParameters) Category() category { return categoryTransport } 428 func (e eventTransportParameters) Name() string { 429 if e.Restore { 430 return "parameters_restored" 431 } 432 return "parameters_set" 433 } 434 func (e eventTransportParameters) IsNil() bool { return false } 435 436 func (e eventTransportParameters) MarshalJSONObject(enc *gojay.Encoder) { 437 if !e.Restore { 438 enc.StringKey("owner", e.Owner.String()) 439 if e.SentBy == protocol.PerspectiveServer { 440 enc.StringKey("original_destination_connection_id", e.OriginalDestinationConnectionID.String()) 441 if e.StatelessResetToken != nil { 442 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", e.StatelessResetToken[:])) 443 } 444 if e.RetrySourceConnectionID != nil { 445 enc.StringKey("retry_source_connection_id", (*e.RetrySourceConnectionID).String()) 446 } 447 } 448 enc.StringKey("initial_source_connection_id", e.InitialSourceConnectionID.String()) 449 } 450 enc.BoolKey("disable_active_migration", e.DisableActiveMigration) 451 enc.FloatKeyOmitEmpty("max_idle_timeout", milliseconds(e.MaxIdleTimeout)) 452 enc.Int64KeyNullEmpty("max_udp_payload_size", int64(e.MaxUDPPayloadSize)) 453 enc.Uint8KeyOmitEmpty("ack_delay_exponent", e.AckDelayExponent) 454 enc.FloatKeyOmitEmpty("max_ack_delay", milliseconds(e.MaxAckDelay)) 455 enc.Uint64KeyOmitEmpty("active_connection_id_limit", e.ActiveConnectionIDLimit) 456 457 enc.Int64KeyOmitEmpty("initial_max_data", int64(e.InitialMaxData)) 458 enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_local", int64(e.InitialMaxStreamDataBidiLocal)) 459 enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_remote", int64(e.InitialMaxStreamDataBidiRemote)) 460 enc.Int64KeyOmitEmpty("initial_max_stream_data_uni", int64(e.InitialMaxStreamDataUni)) 461 enc.Int64KeyOmitEmpty("initial_max_streams_bidi", e.InitialMaxStreamsBidi) 462 enc.Int64KeyOmitEmpty("initial_max_streams_uni", e.InitialMaxStreamsUni) 463 464 if e.PreferredAddress != nil { 465 enc.ObjectKey("preferred_address", e.PreferredAddress) 466 } 467 if e.MaxDatagramFrameSize != protocol.InvalidByteCount { 468 enc.Int64Key("max_datagram_frame_size", int64(e.MaxDatagramFrameSize)) 469 } 470 } 471 472 type preferredAddress struct { 473 IPv4, IPv6 netip.AddrPort 474 ConnectionID protocol.ConnectionID 475 StatelessResetToken protocol.StatelessResetToken 476 } 477 478 var _ gojay.MarshalerJSONObject = &preferredAddress{} 479 480 func (a preferredAddress) IsNil() bool { return false } 481 func (a preferredAddress) MarshalJSONObject(enc *gojay.Encoder) { 482 enc.StringKey("ip_v4", a.IPv4.Addr().String()) 483 enc.Uint16Key("port_v4", a.IPv4.Port()) 484 enc.StringKey("ip_v6", a.IPv6.Addr().String()) 485 enc.Uint16Key("port_v6", a.IPv6.Port()) 486 enc.StringKey("connection_id", a.ConnectionID.String()) 487 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", a.StatelessResetToken)) 488 } 489 490 type eventLossTimerSet struct { 491 TimerType timerType 492 EncLevel protocol.EncryptionLevel 493 Delta time.Duration 494 } 495 496 func (e eventLossTimerSet) Category() category { return categoryRecovery } 497 func (e eventLossTimerSet) Name() string { return "loss_timer_updated" } 498 func (e eventLossTimerSet) IsNil() bool { return false } 499 500 func (e eventLossTimerSet) MarshalJSONObject(enc *gojay.Encoder) { 501 enc.StringKey("event_type", "set") 502 enc.StringKey("timer_type", e.TimerType.String()) 503 enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel)) 504 enc.Float64Key("delta", milliseconds(e.Delta)) 505 } 506 507 type eventLossTimerExpired struct { 508 TimerType timerType 509 EncLevel protocol.EncryptionLevel 510 } 511 512 func (e eventLossTimerExpired) Category() category { return categoryRecovery } 513 func (e eventLossTimerExpired) Name() string { return "loss_timer_updated" } 514 func (e eventLossTimerExpired) IsNil() bool { return false } 515 516 func (e eventLossTimerExpired) MarshalJSONObject(enc *gojay.Encoder) { 517 enc.StringKey("event_type", "expired") 518 enc.StringKey("timer_type", e.TimerType.String()) 519 enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel)) 520 } 521 522 type eventLossTimerCanceled struct{} 523 524 func (e eventLossTimerCanceled) Category() category { return categoryRecovery } 525 func (e eventLossTimerCanceled) Name() string { return "loss_timer_updated" } 526 func (e eventLossTimerCanceled) IsNil() bool { return false } 527 528 func (e eventLossTimerCanceled) MarshalJSONObject(enc *gojay.Encoder) { 529 enc.StringKey("event_type", "cancelled") 530 } 531 532 type eventCongestionStateUpdated struct { 533 state congestionState 534 } 535 536 func (e eventCongestionStateUpdated) Category() category { return categoryRecovery } 537 func (e eventCongestionStateUpdated) Name() string { return "congestion_state_updated" } 538 func (e eventCongestionStateUpdated) IsNil() bool { return false } 539 540 func (e eventCongestionStateUpdated) MarshalJSONObject(enc *gojay.Encoder) { 541 enc.StringKey("new", e.state.String()) 542 } 543 544 type eventECNStateUpdated struct { 545 state logging.ECNState 546 trigger logging.ECNStateTrigger 547 } 548 549 func (e eventECNStateUpdated) Category() category { return categoryRecovery } 550 func (e eventECNStateUpdated) Name() string { return "ecn_state_updated" } 551 func (e eventECNStateUpdated) IsNil() bool { return false } 552 553 func (e eventECNStateUpdated) MarshalJSONObject(enc *gojay.Encoder) { 554 enc.StringKey("new", ecnState(e.state).String()) 555 enc.StringKeyOmitEmpty("trigger", ecnStateTrigger(e.trigger).String()) 556 } 557 558 type eventGeneric struct { 559 name string 560 msg string 561 } 562 563 func (e eventGeneric) Category() category { return categoryTransport } 564 func (e eventGeneric) Name() string { return e.name } 565 func (e eventGeneric) IsNil() bool { return false } 566 567 func (e eventGeneric) MarshalJSONObject(enc *gojay.Encoder) { 568 enc.StringKey("details", e.msg) 569 } 570 571 type eventALPNInformation struct { 572 chosenALPN string 573 } 574 575 func (e eventALPNInformation) Category() category { return categoryTransport } 576 func (e eventALPNInformation) Name() string { return "alpn_information" } 577 func (e eventALPNInformation) IsNil() bool { return false } 578 579 func (e eventALPNInformation) MarshalJSONObject(enc *gojay.Encoder) { 580 enc.StringKey("chosen_alpn", e.chosenALPN) 581 }