1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
package metrics
import (
"errors"
"fmt"
"net"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/logging"
"github.com/prometheus/client_golang/prometheus"
)
const metricNamespace = "quicgo"
func getIPVersion(addr net.Addr) string {
udpAddr, ok := addr.(*net.UDPAddr)
if !ok {
return ""
}
if udpAddr.IP.To4() != nil {
return "ipv4"
}
return "ipv6"
}
var (
connsRejected = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: metricNamespace,
Name: "server_connections_rejected_total",
Help: "Connections Rejected",
},
[]string{"ip_version", "reason"},
)
packetDropped = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: metricNamespace,
Name: "server_received_packets_dropped_total",
Help: "packets dropped",
},
[]string{"ip_version", "reason"},
)
)
// NewTracer creates a new tracer using the default Prometheus registerer.
// The Tracer returned from this function can be used to collect metrics for
// events happening before the establishment of a QUIC connection.
// It can be set on the Tracer field of quic.Transport.
func NewTracer() *logging.Tracer {
return NewTracerWithRegisterer(prometheus.DefaultRegisterer)
}
// NewTracerWithRegisterer creates a new tracer using a given Prometheus registerer.
func NewTracerWithRegisterer(registerer prometheus.Registerer) *logging.Tracer {
for _, c := range [...]prometheus.Collector{
connsRejected,
packetDropped,
} {
if err := registerer.Register(c); err != nil {
if ok := errors.As(err, &prometheus.AlreadyRegisteredError{}); !ok {
panic(err)
}
}
}
return &logging.Tracer{
SentPacket: func(addr net.Addr, hdr *logging.Header, _ logging.ByteCount, frames []logging.Frame) {
tags := getStringSlice()
defer putStringSlice(tags)
var reason string
//nolint:exhaustive // we only care about Retry and Initial packets here
switch hdr.Type {
case protocol.PacketTypeRetry:
reason = "retry"
case protocol.PacketTypeInitial:
var ccf *logging.ConnectionCloseFrame
for _, f := range frames {
cc, ok := f.(*logging.ConnectionCloseFrame)
if ok {
ccf = cc
break
}
}
// This should never happen. We only send Initials before creating the connection in order to
// reject a connection attempt.
if ccf == nil {
return
}
if ccf.IsApplicationError {
//nolint:exhaustive // Only a few error codes applicable.
switch qerr.TransportErrorCode(ccf.ErrorCode) {
case qerr.ConnectionRefused:
reason = "connection_refused"
case qerr.InvalidToken:
reason = "invalid_token"
default:
// This shouldn't happen, the server doesn't send CONNECTION_CLOSE frames with different errors.
reason = fmt.Sprintf("transport_error: %d", ccf.ErrorCode)
}
} else {
// This shouldn't happen, the server doesn't send application-level CONNECTION_CLOSE frames.
reason = "application_error"
}
}
*tags = append(*tags, getIPVersion(addr))
*tags = append(*tags, reason)
connsRejected.WithLabelValues(*tags...).Inc()
},
SentVersionNegotiationPacket: func(addr net.Addr, _, _ logging.ArbitraryLenConnectionID, _ []logging.Version) {
tags := getStringSlice()
defer putStringSlice(tags)
*tags = append(*tags, getIPVersion(addr))
*tags = append(*tags, "version_negotiation")
connsRejected.WithLabelValues(*tags...).Inc()
},
DroppedPacket: func(addr net.Addr, pt logging.PacketType, _ logging.ByteCount, reason logging.PacketDropReason) {
tags := getStringSlice()
defer putStringSlice(tags)
var dropReason string
//nolint:exhaustive // Only a few drop reasons applicable.
switch reason {
case logging.PacketDropDOSPrevention:
if pt == logging.PacketType0RTT {
dropReason = "0rtt_dos_prevention"
} else {
dropReason = "dos_prevention"
}
case logging.PacketDropHeaderParseError:
dropReason = "header_parsing"
case logging.PacketDropPayloadDecryptError:
dropReason = "payload_decrypt"
case logging.PacketDropUnexpectedPacket:
dropReason = "unexpected_packet"
default:
dropReason = "unknown"
}
*tags = append(*tags, getIPVersion(addr))
*tags = append(*tags, dropReason)
packetDropped.WithLabelValues(*tags...).Inc()
},
}
}
|