530 lines
18 KiB
Go
530 lines
18 KiB
Go
package qlog
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/lucas-clemente/quic-go"
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
"github.com/lucas-clemente/quic-go/internal/utils"
|
|
"github.com/lucas-clemente/quic-go/logging"
|
|
|
|
"github.com/francoispqt/gojay"
|
|
)
|
|
|
|
func milliseconds(dur time.Duration) float64 { return float64(dur.Nanoseconds()) / 1e6 }
|
|
|
|
type eventDetails interface {
|
|
Category() category
|
|
Name() string
|
|
gojay.MarshalerJSONObject
|
|
}
|
|
|
|
type event struct {
|
|
RelativeTime time.Duration
|
|
eventDetails
|
|
}
|
|
|
|
var _ gojay.MarshalerJSONObject = event{}
|
|
|
|
func (e event) IsNil() bool { return false }
|
|
func (e event) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.Float64Key("time", milliseconds(e.RelativeTime))
|
|
enc.StringKey("name", e.Category().String()+":"+e.Name())
|
|
enc.ObjectKey("data", e.eventDetails)
|
|
}
|
|
|
|
type versions []versionNumber
|
|
|
|
func (v versions) IsNil() bool { return false }
|
|
func (v versions) MarshalJSONArray(enc *gojay.Encoder) {
|
|
for _, e := range v {
|
|
enc.AddString(e.String())
|
|
}
|
|
}
|
|
|
|
type rawInfo struct {
|
|
Length logging.ByteCount // full packet length, including header and AEAD authentication tag
|
|
PayloadLength logging.ByteCount // length of the packet payload, excluding AEAD tag
|
|
}
|
|
|
|
func (i rawInfo) IsNil() bool { return false }
|
|
func (i rawInfo) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.Uint64Key("length", uint64(i.Length))
|
|
enc.Uint64KeyOmitEmpty("payload_length", uint64(i.PayloadLength))
|
|
}
|
|
|
|
type eventConnectionStarted struct {
|
|
SrcAddr *net.UDPAddr
|
|
DestAddr *net.UDPAddr
|
|
|
|
SrcConnectionID protocol.ConnectionID
|
|
DestConnectionID protocol.ConnectionID
|
|
}
|
|
|
|
var _ eventDetails = &eventConnectionStarted{}
|
|
|
|
func (e eventConnectionStarted) Category() category { return categoryTransport }
|
|
func (e eventConnectionStarted) Name() string { return "connection_started" }
|
|
func (e eventConnectionStarted) IsNil() bool { return false }
|
|
|
|
func (e eventConnectionStarted) MarshalJSONObject(enc *gojay.Encoder) {
|
|
if utils.IsIPv4(e.SrcAddr.IP) {
|
|
enc.StringKey("ip_version", "ipv4")
|
|
} else {
|
|
enc.StringKey("ip_version", "ipv6")
|
|
}
|
|
enc.StringKey("src_ip", e.SrcAddr.IP.String())
|
|
enc.IntKey("src_port", e.SrcAddr.Port)
|
|
enc.StringKey("dst_ip", e.DestAddr.IP.String())
|
|
enc.IntKey("dst_port", e.DestAddr.Port)
|
|
enc.StringKey("src_cid", connectionID(e.SrcConnectionID).String())
|
|
enc.StringKey("dst_cid", connectionID(e.DestConnectionID).String())
|
|
}
|
|
|
|
type eventVersionNegotiated struct {
|
|
clientVersions, serverVersions []versionNumber
|
|
chosenVersion versionNumber
|
|
}
|
|
|
|
func (e eventVersionNegotiated) Category() category { return categoryTransport }
|
|
func (e eventVersionNegotiated) Name() string { return "version_information" }
|
|
func (e eventVersionNegotiated) IsNil() bool { return false }
|
|
|
|
func (e eventVersionNegotiated) MarshalJSONObject(enc *gojay.Encoder) {
|
|
if len(e.clientVersions) > 0 {
|
|
enc.ArrayKey("client_versions", versions(e.clientVersions))
|
|
}
|
|
if len(e.serverVersions) > 0 {
|
|
enc.ArrayKey("server_versions", versions(e.serverVersions))
|
|
}
|
|
enc.StringKey("chosen_version", e.chosenVersion.String())
|
|
}
|
|
|
|
type eventConnectionClosed struct {
|
|
e error
|
|
}
|
|
|
|
func (e eventConnectionClosed) Category() category { return categoryTransport }
|
|
func (e eventConnectionClosed) Name() string { return "connection_closed" }
|
|
func (e eventConnectionClosed) IsNil() bool { return false }
|
|
|
|
func (e eventConnectionClosed) MarshalJSONObject(enc *gojay.Encoder) {
|
|
var (
|
|
statelessResetErr *quic.StatelessResetError
|
|
handshakeTimeoutErr *quic.HandshakeTimeoutError
|
|
idleTimeoutErr *quic.IdleTimeoutError
|
|
applicationErr *quic.ApplicationError
|
|
transportErr *quic.TransportError
|
|
versionNegotiationErr *quic.VersionNegotiationError
|
|
)
|
|
switch {
|
|
case errors.As(e.e, &statelessResetErr):
|
|
enc.StringKey("owner", ownerRemote.String())
|
|
enc.StringKey("trigger", "stateless_reset")
|
|
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", statelessResetErr.Token))
|
|
case errors.As(e.e, &handshakeTimeoutErr):
|
|
enc.StringKey("owner", ownerLocal.String())
|
|
enc.StringKey("trigger", "handshake_timeout")
|
|
case errors.As(e.e, &idleTimeoutErr):
|
|
enc.StringKey("owner", ownerLocal.String())
|
|
enc.StringKey("trigger", "idle_timeout")
|
|
case errors.As(e.e, &applicationErr):
|
|
owner := ownerLocal
|
|
if applicationErr.Remote {
|
|
owner = ownerRemote
|
|
}
|
|
enc.StringKey("owner", owner.String())
|
|
enc.Uint64Key("application_code", uint64(applicationErr.ErrorCode))
|
|
enc.StringKey("reason", applicationErr.ErrorMessage)
|
|
case errors.As(e.e, &transportErr):
|
|
owner := ownerLocal
|
|
if transportErr.Remote {
|
|
owner = ownerRemote
|
|
}
|
|
enc.StringKey("owner", owner.String())
|
|
enc.StringKey("connection_code", transportError(transportErr.ErrorCode).String())
|
|
enc.StringKey("reason", transportErr.ErrorMessage)
|
|
case errors.As(e.e, &versionNegotiationErr):
|
|
enc.StringKey("owner", ownerRemote.String())
|
|
enc.StringKey("trigger", "version_negotiation")
|
|
}
|
|
}
|
|
|
|
type eventPacketSent struct {
|
|
Header packetHeader
|
|
Length logging.ByteCount
|
|
PayloadLength logging.ByteCount
|
|
Frames frames
|
|
IsCoalesced bool
|
|
Trigger string
|
|
}
|
|
|
|
var _ eventDetails = eventPacketSent{}
|
|
|
|
func (e eventPacketSent) Category() category { return categoryTransport }
|
|
func (e eventPacketSent) Name() string { return "packet_sent" }
|
|
func (e eventPacketSent) IsNil() bool { return false }
|
|
|
|
func (e eventPacketSent) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.ObjectKey("header", e.Header)
|
|
enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength})
|
|
enc.ArrayKeyOmitEmpty("frames", e.Frames)
|
|
enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced)
|
|
enc.StringKeyOmitEmpty("trigger", e.Trigger)
|
|
}
|
|
|
|
type eventPacketReceived struct {
|
|
Header packetHeader
|
|
Length logging.ByteCount
|
|
PayloadLength logging.ByteCount
|
|
Frames frames
|
|
IsCoalesced bool
|
|
Trigger string
|
|
}
|
|
|
|
var _ eventDetails = eventPacketReceived{}
|
|
|
|
func (e eventPacketReceived) Category() category { return categoryTransport }
|
|
func (e eventPacketReceived) Name() string { return "packet_received" }
|
|
func (e eventPacketReceived) IsNil() bool { return false }
|
|
|
|
func (e eventPacketReceived) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.ObjectKey("header", e.Header)
|
|
enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength})
|
|
enc.ArrayKeyOmitEmpty("frames", e.Frames)
|
|
enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced)
|
|
enc.StringKeyOmitEmpty("trigger", e.Trigger)
|
|
}
|
|
|
|
type eventRetryReceived struct {
|
|
Header packetHeader
|
|
}
|
|
|
|
func (e eventRetryReceived) Category() category { return categoryTransport }
|
|
func (e eventRetryReceived) Name() string { return "packet_received" }
|
|
func (e eventRetryReceived) IsNil() bool { return false }
|
|
|
|
func (e eventRetryReceived) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.ObjectKey("header", e.Header)
|
|
}
|
|
|
|
type eventVersionNegotiationReceived struct {
|
|
Header packetHeader
|
|
SupportedVersions []versionNumber
|
|
}
|
|
|
|
func (e eventVersionNegotiationReceived) Category() category { return categoryTransport }
|
|
func (e eventVersionNegotiationReceived) Name() string { return "packet_received" }
|
|
func (e eventVersionNegotiationReceived) IsNil() bool { return false }
|
|
|
|
func (e eventVersionNegotiationReceived) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.ObjectKey("header", e.Header)
|
|
enc.ArrayKey("supported_versions", versions(e.SupportedVersions))
|
|
}
|
|
|
|
type eventPacketBuffered struct {
|
|
PacketType logging.PacketType
|
|
}
|
|
|
|
func (e eventPacketBuffered) Category() category { return categoryTransport }
|
|
func (e eventPacketBuffered) Name() string { return "packet_buffered" }
|
|
func (e eventPacketBuffered) IsNil() bool { return false }
|
|
|
|
func (e eventPacketBuffered) MarshalJSONObject(enc *gojay.Encoder) {
|
|
//nolint:gosimple
|
|
enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType})
|
|
enc.StringKey("trigger", "keys_unavailable")
|
|
}
|
|
|
|
type eventPacketDropped struct {
|
|
PacketType logging.PacketType
|
|
PacketSize protocol.ByteCount
|
|
Trigger packetDropReason
|
|
}
|
|
|
|
func (e eventPacketDropped) Category() category { return categoryTransport }
|
|
func (e eventPacketDropped) Name() string { return "packet_dropped" }
|
|
func (e eventPacketDropped) IsNil() bool { return false }
|
|
|
|
func (e eventPacketDropped) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType})
|
|
enc.ObjectKey("raw", rawInfo{Length: e.PacketSize})
|
|
enc.StringKey("trigger", e.Trigger.String())
|
|
}
|
|
|
|
type metrics struct {
|
|
MinRTT time.Duration
|
|
SmoothedRTT time.Duration
|
|
LatestRTT time.Duration
|
|
RTTVariance time.Duration
|
|
|
|
CongestionWindow protocol.ByteCount
|
|
BytesInFlight protocol.ByteCount
|
|
PacketsInFlight int
|
|
}
|
|
|
|
type eventMetricsUpdated struct {
|
|
Last *metrics
|
|
Current *metrics
|
|
}
|
|
|
|
func (e eventMetricsUpdated) Category() category { return categoryRecovery }
|
|
func (e eventMetricsUpdated) Name() string { return "metrics_updated" }
|
|
func (e eventMetricsUpdated) IsNil() bool { return false }
|
|
|
|
func (e eventMetricsUpdated) MarshalJSONObject(enc *gojay.Encoder) {
|
|
if e.Last == nil || e.Last.MinRTT != e.Current.MinRTT {
|
|
enc.FloatKey("min_rtt", milliseconds(e.Current.MinRTT))
|
|
}
|
|
if e.Last == nil || e.Last.SmoothedRTT != e.Current.SmoothedRTT {
|
|
enc.FloatKey("smoothed_rtt", milliseconds(e.Current.SmoothedRTT))
|
|
}
|
|
if e.Last == nil || e.Last.LatestRTT != e.Current.LatestRTT {
|
|
enc.FloatKey("latest_rtt", milliseconds(e.Current.LatestRTT))
|
|
}
|
|
if e.Last == nil || e.Last.RTTVariance != e.Current.RTTVariance {
|
|
enc.FloatKey("rtt_variance", milliseconds(e.Current.RTTVariance))
|
|
}
|
|
|
|
if e.Last == nil || e.Last.CongestionWindow != e.Current.CongestionWindow {
|
|
enc.Uint64Key("congestion_window", uint64(e.Current.CongestionWindow))
|
|
}
|
|
if e.Last == nil || e.Last.BytesInFlight != e.Current.BytesInFlight {
|
|
enc.Uint64Key("bytes_in_flight", uint64(e.Current.BytesInFlight))
|
|
}
|
|
if e.Last == nil || e.Last.PacketsInFlight != e.Current.PacketsInFlight {
|
|
enc.Uint64KeyOmitEmpty("packets_in_flight", uint64(e.Current.PacketsInFlight))
|
|
}
|
|
}
|
|
|
|
type eventUpdatedPTO struct {
|
|
Value uint32
|
|
}
|
|
|
|
func (e eventUpdatedPTO) Category() category { return categoryRecovery }
|
|
func (e eventUpdatedPTO) Name() string { return "metrics_updated" }
|
|
func (e eventUpdatedPTO) IsNil() bool { return false }
|
|
|
|
func (e eventUpdatedPTO) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.Uint32Key("pto_count", e.Value)
|
|
}
|
|
|
|
type eventPacketLost struct {
|
|
PacketType logging.PacketType
|
|
PacketNumber protocol.PacketNumber
|
|
Trigger packetLossReason
|
|
}
|
|
|
|
func (e eventPacketLost) Category() category { return categoryRecovery }
|
|
func (e eventPacketLost) Name() string { return "packet_lost" }
|
|
func (e eventPacketLost) IsNil() bool { return false }
|
|
|
|
func (e eventPacketLost) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.ObjectKey("header", packetHeaderWithTypeAndPacketNumber{
|
|
PacketType: e.PacketType,
|
|
PacketNumber: e.PacketNumber,
|
|
})
|
|
enc.StringKey("trigger", e.Trigger.String())
|
|
}
|
|
|
|
type eventKeyUpdated struct {
|
|
Trigger keyUpdateTrigger
|
|
KeyType keyType
|
|
Generation protocol.KeyPhase
|
|
// we don't log the keys here, so we don't need `old` and `new`.
|
|
}
|
|
|
|
func (e eventKeyUpdated) Category() category { return categorySecurity }
|
|
func (e eventKeyUpdated) Name() string { return "key_updated" }
|
|
func (e eventKeyUpdated) IsNil() bool { return false }
|
|
|
|
func (e eventKeyUpdated) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.StringKey("trigger", e.Trigger.String())
|
|
enc.StringKey("key_type", e.KeyType.String())
|
|
if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT {
|
|
enc.Uint64Key("generation", uint64(e.Generation))
|
|
}
|
|
}
|
|
|
|
type eventKeyRetired struct {
|
|
KeyType keyType
|
|
Generation protocol.KeyPhase
|
|
}
|
|
|
|
func (e eventKeyRetired) Category() category { return categorySecurity }
|
|
func (e eventKeyRetired) Name() string { return "key_retired" }
|
|
func (e eventKeyRetired) IsNil() bool { return false }
|
|
|
|
func (e eventKeyRetired) MarshalJSONObject(enc *gojay.Encoder) {
|
|
if e.KeyType != keyTypeClient1RTT && e.KeyType != keyTypeServer1RTT {
|
|
enc.StringKey("trigger", "tls")
|
|
}
|
|
enc.StringKey("key_type", e.KeyType.String())
|
|
if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT {
|
|
enc.Uint64Key("generation", uint64(e.Generation))
|
|
}
|
|
}
|
|
|
|
type eventTransportParameters struct {
|
|
Restore bool
|
|
Owner owner
|
|
SentBy protocol.Perspective
|
|
|
|
OriginalDestinationConnectionID protocol.ConnectionID
|
|
InitialSourceConnectionID protocol.ConnectionID
|
|
RetrySourceConnectionID *protocol.ConnectionID
|
|
|
|
StatelessResetToken *protocol.StatelessResetToken
|
|
DisableActiveMigration bool
|
|
MaxIdleTimeout time.Duration
|
|
MaxUDPPayloadSize protocol.ByteCount
|
|
AckDelayExponent uint8
|
|
MaxAckDelay time.Duration
|
|
ActiveConnectionIDLimit uint64
|
|
|
|
InitialMaxData protocol.ByteCount
|
|
InitialMaxStreamDataBidiLocal protocol.ByteCount
|
|
InitialMaxStreamDataBidiRemote protocol.ByteCount
|
|
InitialMaxStreamDataUni protocol.ByteCount
|
|
InitialMaxStreamsBidi int64
|
|
InitialMaxStreamsUni int64
|
|
|
|
PreferredAddress *preferredAddress
|
|
|
|
MaxDatagramFrameSize protocol.ByteCount
|
|
}
|
|
|
|
func (e eventTransportParameters) Category() category { return categoryTransport }
|
|
func (e eventTransportParameters) Name() string {
|
|
if e.Restore {
|
|
return "parameters_restored"
|
|
}
|
|
return "parameters_set"
|
|
}
|
|
func (e eventTransportParameters) IsNil() bool { return false }
|
|
|
|
func (e eventTransportParameters) MarshalJSONObject(enc *gojay.Encoder) {
|
|
if !e.Restore {
|
|
enc.StringKey("owner", e.Owner.String())
|
|
if e.SentBy == protocol.PerspectiveServer {
|
|
enc.StringKey("original_destination_connection_id", connectionID(e.OriginalDestinationConnectionID).String())
|
|
if e.StatelessResetToken != nil {
|
|
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", e.StatelessResetToken[:]))
|
|
}
|
|
if e.RetrySourceConnectionID != nil {
|
|
enc.StringKey("retry_source_connection_id", connectionID(*e.RetrySourceConnectionID).String())
|
|
}
|
|
}
|
|
enc.StringKey("initial_source_connection_id", connectionID(e.InitialSourceConnectionID).String())
|
|
}
|
|
enc.BoolKey("disable_active_migration", e.DisableActiveMigration)
|
|
enc.FloatKeyOmitEmpty("max_idle_timeout", milliseconds(e.MaxIdleTimeout))
|
|
enc.Int64KeyNullEmpty("max_udp_payload_size", int64(e.MaxUDPPayloadSize))
|
|
enc.Uint8KeyOmitEmpty("ack_delay_exponent", e.AckDelayExponent)
|
|
enc.FloatKeyOmitEmpty("max_ack_delay", milliseconds(e.MaxAckDelay))
|
|
enc.Uint64KeyOmitEmpty("active_connection_id_limit", e.ActiveConnectionIDLimit)
|
|
|
|
enc.Int64KeyOmitEmpty("initial_max_data", int64(e.InitialMaxData))
|
|
enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_local", int64(e.InitialMaxStreamDataBidiLocal))
|
|
enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_remote", int64(e.InitialMaxStreamDataBidiRemote))
|
|
enc.Int64KeyOmitEmpty("initial_max_stream_data_uni", int64(e.InitialMaxStreamDataUni))
|
|
enc.Int64KeyOmitEmpty("initial_max_streams_bidi", e.InitialMaxStreamsBidi)
|
|
enc.Int64KeyOmitEmpty("initial_max_streams_uni", e.InitialMaxStreamsUni)
|
|
|
|
if e.PreferredAddress != nil {
|
|
enc.ObjectKey("preferred_address", e.PreferredAddress)
|
|
}
|
|
if e.MaxDatagramFrameSize != protocol.InvalidByteCount {
|
|
enc.Int64Key("max_datagram_frame_size", int64(e.MaxDatagramFrameSize))
|
|
}
|
|
}
|
|
|
|
type preferredAddress struct {
|
|
IPv4, IPv6 net.IP
|
|
PortV4, PortV6 uint16
|
|
ConnectionID protocol.ConnectionID
|
|
StatelessResetToken protocol.StatelessResetToken
|
|
}
|
|
|
|
var _ gojay.MarshalerJSONObject = &preferredAddress{}
|
|
|
|
func (a preferredAddress) IsNil() bool { return false }
|
|
func (a preferredAddress) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.StringKey("ip_v4", a.IPv4.String())
|
|
enc.Uint16Key("port_v4", a.PortV4)
|
|
enc.StringKey("ip_v6", a.IPv6.String())
|
|
enc.Uint16Key("port_v6", a.PortV6)
|
|
enc.StringKey("connection_id", connectionID(a.ConnectionID).String())
|
|
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", a.StatelessResetToken))
|
|
}
|
|
|
|
type eventLossTimerSet struct {
|
|
TimerType timerType
|
|
EncLevel protocol.EncryptionLevel
|
|
Delta time.Duration
|
|
}
|
|
|
|
func (e eventLossTimerSet) Category() category { return categoryRecovery }
|
|
func (e eventLossTimerSet) Name() string { return "loss_timer_updated" }
|
|
func (e eventLossTimerSet) IsNil() bool { return false }
|
|
|
|
func (e eventLossTimerSet) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.StringKey("event_type", "set")
|
|
enc.StringKey("timer_type", e.TimerType.String())
|
|
enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel))
|
|
enc.Float64Key("delta", milliseconds(e.Delta))
|
|
}
|
|
|
|
type eventLossTimerExpired struct {
|
|
TimerType timerType
|
|
EncLevel protocol.EncryptionLevel
|
|
}
|
|
|
|
func (e eventLossTimerExpired) Category() category { return categoryRecovery }
|
|
func (e eventLossTimerExpired) Name() string { return "loss_timer_updated" }
|
|
func (e eventLossTimerExpired) IsNil() bool { return false }
|
|
|
|
func (e eventLossTimerExpired) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.StringKey("event_type", "expired")
|
|
enc.StringKey("timer_type", e.TimerType.String())
|
|
enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel))
|
|
}
|
|
|
|
type eventLossTimerCanceled struct{}
|
|
|
|
func (e eventLossTimerCanceled) Category() category { return categoryRecovery }
|
|
func (e eventLossTimerCanceled) Name() string { return "loss_timer_updated" }
|
|
func (e eventLossTimerCanceled) IsNil() bool { return false }
|
|
|
|
func (e eventLossTimerCanceled) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.StringKey("event_type", "cancelled")
|
|
}
|
|
|
|
type eventCongestionStateUpdated struct {
|
|
state congestionState
|
|
}
|
|
|
|
func (e eventCongestionStateUpdated) Category() category { return categoryRecovery }
|
|
func (e eventCongestionStateUpdated) Name() string { return "congestion_state_updated" }
|
|
func (e eventCongestionStateUpdated) IsNil() bool { return false }
|
|
|
|
func (e eventCongestionStateUpdated) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.StringKey("new", e.state.String())
|
|
}
|
|
|
|
type eventGeneric struct {
|
|
name string
|
|
msg string
|
|
}
|
|
|
|
func (e eventGeneric) Category() category { return categoryTransport }
|
|
func (e eventGeneric) Name() string { return e.name }
|
|
func (e eventGeneric) IsNil() bool { return false }
|
|
|
|
func (e eventGeneric) MarshalJSONObject(enc *gojay.Encoder) {
|
|
enc.StringKey("details", e.msg)
|
|
}
|