cloudflared-mirror/quic/metrics.go

230 lines
6.7 KiB
Go

package quic
import (
"reflect"
"strings"
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/quic-go/quic-go/logging"
)
const (
namespace = "quic"
)
var (
clientConnLabels = []string{"conn_index"}
clientMetrics = struct {
totalConnections prometheus.Counter
closedConnections prometheus.Counter
sentFrames *prometheus.CounterVec
sentBytes *prometheus.CounterVec
receivedFrames *prometheus.CounterVec
receivedBytes *prometheus.CounterVec
bufferedPackets *prometheus.CounterVec
droppedPackets *prometheus.CounterVec
lostPackets *prometheus.CounterVec
minRTT *prometheus.GaugeVec
latestRTT *prometheus.GaugeVec
smoothedRTT *prometheus.GaugeVec
}{
totalConnections: prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "total_connections",
Help: "Number of connections initiated",
},
),
closedConnections: prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "closed_connections",
Help: "Number of connections that has been closed",
},
),
sentFrames: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "sent_frames",
Help: "Number of frames that have been sent through a connection",
},
append(clientConnLabels, "frame_type"),
),
sentBytes: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "sent_bytes",
Help: "Number of bytes that have been sent through a connection",
},
clientConnLabels,
),
receivedFrames: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "received_frames",
Help: "Number of frames that have been received through a connection",
},
append(clientConnLabels, "frame_type"),
),
receivedBytes: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "receive_bytes",
Help: "Number of bytes that have been received through a connection",
},
clientConnLabels,
),
bufferedPackets: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "buffered_packets",
Help: "Number of bytes that have been buffered on a connection",
},
append(clientConnLabels, "packet_type"),
),
droppedPackets: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "dropped_packets",
Help: "Number of bytes that have been dropped on a connection",
},
append(clientConnLabels, "packet_type", "reason"),
),
lostPackets: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "lost_packets",
Help: "Number of packets that have been lost from a connection",
},
append(clientConnLabels, "reason"),
),
minRTT: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "client",
Name: "min_rtt",
Help: "Lowest RTT measured on a connection in millisec",
},
clientConnLabels,
),
latestRTT: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "client",
Name: "latest_rtt",
Help: "Latest RTT measured on a connection",
},
clientConnLabels,
),
smoothedRTT: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "client",
Name: "smoothed_rtt",
Help: "Calculated smoothed RTT measured on a connection in millisec",
},
clientConnLabels,
),
}
registerClient = sync.Once{}
packetTooBigDropped = prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "client",
Name: "packet_too_big_dropped",
Help: "Count of packets received from origin that are too big to send to the edge and are dropped as a result",
})
)
type clientCollector struct {
index string
}
func newClientCollector(index uint8) *clientCollector {
registerClient.Do(func() {
prometheus.MustRegister(
clientMetrics.totalConnections,
clientMetrics.closedConnections,
clientMetrics.sentFrames,
clientMetrics.sentBytes,
clientMetrics.receivedFrames,
clientMetrics.receivedBytes,
clientMetrics.bufferedPackets,
clientMetrics.droppedPackets,
clientMetrics.lostPackets,
clientMetrics.minRTT,
clientMetrics.latestRTT,
clientMetrics.smoothedRTT,
packetTooBigDropped,
)
})
return &clientCollector{
index: uint8ToString(index),
}
}
func (cc *clientCollector) startedConnection() {
clientMetrics.totalConnections.Inc()
}
func (cc *clientCollector) closedConnection(err error) {
clientMetrics.closedConnections.Inc()
}
func (cc *clientCollector) sentPackets(size logging.ByteCount, frames []logging.Frame) {
cc.collectPackets(size, frames, clientMetrics.sentFrames, clientMetrics.sentBytes)
}
func (cc *clientCollector) receivedPackets(size logging.ByteCount, frames []logging.Frame) {
cc.collectPackets(size, frames, clientMetrics.receivedFrames, clientMetrics.receivedBytes)
}
func (cc *clientCollector) bufferedPackets(packetType logging.PacketType) {
clientMetrics.bufferedPackets.WithLabelValues(cc.index, packetTypeString(packetType)).Inc()
}
func (cc *clientCollector) droppedPackets(packetType logging.PacketType, size logging.ByteCount, reason logging.PacketDropReason) {
clientMetrics.droppedPackets.WithLabelValues(
cc.index,
packetTypeString(packetType),
packetDropReasonString(reason),
).Add(byteCountToPromCount(size))
}
func (cc *clientCollector) lostPackets(reason logging.PacketLossReason) {
clientMetrics.lostPackets.WithLabelValues(cc.index, packetLossReasonString(reason)).Inc()
}
func (cc *clientCollector) updatedRTT(rtt *logging.RTTStats) {
clientMetrics.minRTT.WithLabelValues(cc.index).Set(durationToPromGauge(rtt.MinRTT()))
clientMetrics.latestRTT.WithLabelValues(cc.index).Set(durationToPromGauge(rtt.LatestRTT()))
clientMetrics.smoothedRTT.WithLabelValues(cc.index).Set(durationToPromGauge(rtt.SmoothedRTT()))
}
func (cc *clientCollector) collectPackets(size logging.ByteCount, frames []logging.Frame, counter, bandwidth *prometheus.CounterVec) {
for _, frame := range frames {
counter.WithLabelValues(cc.index, frameName(frame)).Inc()
}
bandwidth.WithLabelValues(cc.index).Add(byteCountToPromCount(size))
}
func frameName(frame logging.Frame) string {
if frame == nil {
return "nil"
} else {
name := reflect.TypeOf(frame).Elem().Name()
return strings.TrimSuffix(name, "Frame")
}
}