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