2021-10-15 11:05:54 +00:00
package quic
import (
2024-02-16 11:28:59 +00:00
"reflect"
"strings"
2021-10-15 11:05:54 +00:00
"sync"
"github.com/prometheus/client_golang/prometheus"
2023-05-06 00:42:41 +00:00
"github.com/quic-go/quic-go/logging"
2024-06-06 20:02:18 +00:00
"github.com/rs/zerolog"
2021-10-15 11:05:54 +00:00
)
const (
namespace = "quic"
)
var (
clientConnLabels = [ ] string { "conn_index" }
clientMetrics = struct {
totalConnections prometheus . Counter
2022-12-07 11:04:32 +00:00
closedConnections prometheus . Counter
2024-06-06 20:02:18 +00:00
maxUDPPayloadSize * prometheus . GaugeVec
2024-02-16 11:28:59 +00:00
sentFrames * prometheus . CounterVec
2021-10-15 11:05:54 +00:00
sentBytes * prometheus . CounterVec
2024-02-16 11:28:59 +00:00
receivedFrames * prometheus . CounterVec
receivedBytes * prometheus . CounterVec
2021-10-15 11:05:54 +00:00
bufferedPackets * prometheus . CounterVec
droppedPackets * prometheus . CounterVec
lostPackets * prometheus . CounterVec
minRTT * prometheus . GaugeVec
latestRTT * prometheus . GaugeVec
smoothedRTT * prometheus . GaugeVec
2024-06-07 15:24:19 +00:00
mtu * prometheus . GaugeVec
congestionWindow * prometheus . GaugeVec
congestionState * prometheus . GaugeVec
2021-10-15 11:05:54 +00:00
} {
totalConnections : prometheus . NewCounter (
2024-02-16 11:28:59 +00:00
prometheus . CounterOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "total_connections" ,
Help : "Number of connections initiated" ,
} ,
2021-10-15 11:05:54 +00:00
) ,
2022-12-07 11:04:32 +00:00
closedConnections : prometheus . NewCounter (
2024-02-16 11:28:59 +00:00
prometheus . CounterOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "closed_connections" ,
Help : "Number of connections that has been closed" ,
} ,
2021-10-15 11:05:54 +00:00
) ,
2024-06-06 20:02:18 +00:00
maxUDPPayloadSize : prometheus . NewGaugeVec (
prometheus . GaugeOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "max_udp_payload" ,
Help : "Maximum UDP payload size in bytes for a QUIC packet" ,
} ,
clientConnLabels ,
) ,
2024-02-16 11:28:59 +00:00
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" ) ,
2021-10-15 11:05:54 +00:00
) ,
sentBytes : prometheus . NewCounterVec (
2024-02-16 11:28:59 +00:00
prometheus . CounterOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "sent_bytes" ,
Help : "Number of bytes that have been sent through a connection" ,
} ,
2021-10-15 11:05:54 +00:00
clientConnLabels ,
) ,
2024-02-16 11:28:59 +00:00
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" ) ,
2021-10-15 11:05:54 +00:00
) ,
2024-02-16 11:28:59 +00:00
receivedBytes : prometheus . NewCounterVec (
prometheus . CounterOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "receive_bytes" ,
Help : "Number of bytes that have been received through a connection" ,
} ,
2021-10-15 11:05:54 +00:00
clientConnLabels ,
) ,
bufferedPackets : prometheus . NewCounterVec (
2024-02-16 11:28:59 +00:00
prometheus . CounterOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "buffered_packets" ,
Help : "Number of bytes that have been buffered on a connection" ,
} ,
2021-10-15 11:05:54 +00:00
append ( clientConnLabels , "packet_type" ) ,
) ,
droppedPackets : prometheus . NewCounterVec (
2024-02-16 11:28:59 +00:00
prometheus . CounterOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "dropped_packets" ,
Help : "Number of bytes that have been dropped on a connection" ,
} ,
2021-10-15 11:05:54 +00:00
append ( clientConnLabels , "packet_type" , "reason" ) ,
) ,
lostPackets : prometheus . NewCounterVec (
2024-02-16 11:28:59 +00:00
prometheus . CounterOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "lost_packets" ,
Help : "Number of packets that have been lost from a connection" ,
} ,
2021-10-15 11:05:54 +00:00
append ( clientConnLabels , "reason" ) ,
) ,
minRTT : prometheus . NewGaugeVec (
prometheus . GaugeOpts {
Namespace : namespace ,
2024-02-16 11:28:59 +00:00
Subsystem : "client" ,
2021-10-15 11:05:54 +00:00
Name : "min_rtt" ,
Help : "Lowest RTT measured on a connection in millisec" ,
} ,
clientConnLabels ,
) ,
latestRTT : prometheus . NewGaugeVec (
prometheus . GaugeOpts {
Namespace : namespace ,
2024-02-16 11:28:59 +00:00
Subsystem : "client" ,
2021-10-15 11:05:54 +00:00
Name : "latest_rtt" ,
Help : "Latest RTT measured on a connection" ,
} ,
clientConnLabels ,
) ,
smoothedRTT : prometheus . NewGaugeVec (
prometheus . GaugeOpts {
Namespace : namespace ,
2024-02-16 11:28:59 +00:00
Subsystem : "client" ,
2021-10-15 11:05:54 +00:00
Name : "smoothed_rtt" ,
Help : "Calculated smoothed RTT measured on a connection in millisec" ,
} ,
clientConnLabels ,
) ,
2024-06-07 15:24:19 +00:00
mtu : prometheus . NewGaugeVec (
prometheus . GaugeOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "mtu" ,
Help : "Current maximum transmission unit (MTU) of a connection" ,
} ,
clientConnLabels ,
) ,
congestionWindow : prometheus . NewGaugeVec (
prometheus . GaugeOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "congestion_window" ,
Help : "Current congestion window size" ,
} ,
clientConnLabels ,
) ,
congestionState : prometheus . NewGaugeVec (
prometheus . GaugeOpts {
Namespace : namespace ,
Subsystem : "client" ,
Name : "congestion_state" ,
Help : "Current congestion control state. See https://pkg.go.dev/github.com/quic-go/quic-go@v0.45.0/logging#CongestionState for what each value maps to" ,
} ,
clientConnLabels ,
) ,
2021-10-15 11:05:54 +00:00
}
2024-02-16 11:28:59 +00:00
2021-10-15 11:05:54 +00:00
registerClient = sync . Once { }
2022-08-25 10:05:01 +00:00
packetTooBigDropped = prometheus . NewCounter ( prometheus . CounterOpts {
Namespace : namespace ,
2024-02-16 11:28:59 +00:00
Subsystem : "client" ,
2022-08-25 10:05:01 +00:00
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" ,
} )
2021-10-15 11:05:54 +00:00
)
type clientCollector struct {
2024-06-06 20:02:18 +00:00
index string
logger * zerolog . Logger
2021-10-15 11:05:54 +00:00
}
2024-06-06 20:02:18 +00:00
func newClientCollector ( index string , logger * zerolog . Logger ) * clientCollector {
2021-10-15 11:05:54 +00:00
registerClient . Do ( func ( ) {
prometheus . MustRegister (
clientMetrics . totalConnections ,
clientMetrics . closedConnections ,
2024-06-06 20:02:18 +00:00
clientMetrics . maxUDPPayloadSize ,
2024-02-16 11:28:59 +00:00
clientMetrics . sentFrames ,
2021-10-15 11:05:54 +00:00
clientMetrics . sentBytes ,
2024-02-16 11:28:59 +00:00
clientMetrics . receivedFrames ,
clientMetrics . receivedBytes ,
2021-10-15 11:05:54 +00:00
clientMetrics . bufferedPackets ,
clientMetrics . droppedPackets ,
clientMetrics . lostPackets ,
clientMetrics . minRTT ,
clientMetrics . latestRTT ,
clientMetrics . smoothedRTT ,
2024-06-07 15:24:19 +00:00
clientMetrics . mtu ,
clientMetrics . congestionWindow ,
clientMetrics . congestionState ,
2022-08-25 10:05:01 +00:00
packetTooBigDropped ,
2021-10-15 11:05:54 +00:00
)
} )
2024-06-06 20:02:18 +00:00
2021-10-15 11:05:54 +00:00
return & clientCollector {
2024-06-06 20:02:18 +00:00
index : index ,
logger : logger ,
2021-10-15 11:05:54 +00:00
}
}
func ( cc * clientCollector ) startedConnection ( ) {
clientMetrics . totalConnections . Inc ( )
}
2024-06-06 20:02:18 +00:00
func ( cc * clientCollector ) closedConnection ( error ) {
2022-12-07 11:04:32 +00:00
clientMetrics . closedConnections . Inc ( )
2021-10-15 11:05:54 +00:00
}
2024-06-06 20:02:18 +00:00
func ( cc * clientCollector ) receivedTransportParameters ( params * logging . TransportParameters ) {
clientMetrics . maxUDPPayloadSize . WithLabelValues ( cc . index ) . Set ( float64 ( params . MaxUDPPayloadSize ) )
cc . logger . Debug ( ) . Msgf ( "Received transport parameters: MaxUDPPayloadSize=%d, MaxIdleTimeout=%v, MaxDatagramFrameSize=%d" , params . MaxUDPPayloadSize , params . MaxIdleTimeout , params . MaxDatagramFrameSize )
}
2024-02-16 11:28:59 +00:00
func ( cc * clientCollector ) sentPackets ( size logging . ByteCount , frames [ ] logging . Frame ) {
2024-06-06 20:02:18 +00:00
cc . collectPackets ( size , frames , clientMetrics . sentFrames , clientMetrics . sentBytes , sent )
2021-10-15 11:05:54 +00:00
}
2024-02-16 11:28:59 +00:00
func ( cc * clientCollector ) receivedPackets ( size logging . ByteCount , frames [ ] logging . Frame ) {
2024-06-06 20:02:18 +00:00
cc . collectPackets ( size , frames , clientMetrics . receivedFrames , clientMetrics . receivedBytes , received )
2021-10-15 11:05:54 +00:00
}
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 ( ) ) )
}
2024-06-07 15:24:19 +00:00
func ( cc * clientCollector ) updateCongestionWindow ( size logging . ByteCount ) {
clientMetrics . congestionWindow . WithLabelValues ( cc . index ) . Set ( float64 ( size ) )
}
func ( cc * clientCollector ) updatedCongestionState ( state logging . CongestionState ) {
clientMetrics . congestionState . WithLabelValues ( cc . index ) . Set ( float64 ( state ) )
}
func ( cc * clientCollector ) updateMTU ( mtu logging . ByteCount ) {
clientMetrics . mtu . WithLabelValues ( cc . index ) . Set ( float64 ( mtu ) )
cc . logger . Debug ( ) . Msgf ( "QUIC MTU updated to %d" , mtu )
}
2024-06-06 20:02:18 +00:00
func ( cc * clientCollector ) collectPackets ( size logging . ByteCount , frames [ ] logging . Frame , counter , bandwidth * prometheus . CounterVec , direction direction ) {
2024-02-16 11:28:59 +00:00
for _ , frame := range frames {
2024-06-06 20:02:18 +00:00
switch f := frame . ( type ) {
case logging . DataBlockedFrame :
cc . logger . Debug ( ) . Msgf ( "%s data_blocked frame" , direction )
case logging . StreamDataBlockedFrame :
cc . logger . Debug ( ) . Int64 ( "streamID" , int64 ( f . StreamID ) ) . Msgf ( "%s stream_data_blocked frame" , direction )
}
2024-02-16 11:28:59 +00:00
counter . WithLabelValues ( cc . index , frameName ( frame ) ) . Inc ( )
}
bandwidth . WithLabelValues ( cc . index ) . Add ( byteCountToPromCount ( size ) )
2021-10-15 11:05:54 +00:00
}
2024-02-16 11:28:59 +00:00
func frameName ( frame logging . Frame ) string {
if frame == nil {
return "nil"
} else {
name := reflect . TypeOf ( frame ) . Elem ( ) . Name ( )
return strings . TrimSuffix ( name , "Frame" )
2021-10-15 11:05:54 +00:00
}
}
2024-06-06 20:02:18 +00:00
type direction uint8
const (
sent direction = iota
received
)
func ( d direction ) String ( ) string {
if d == sent {
return "sent"
}
return "received"
}