status-go/vendor/github.com/lucas-clemente/quic-go/qlog/event.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)
}