package relay
import (
"time"
"github.com/libp2p/go-libp2p/p2p/metricshelper"
pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb"
"github.com/prometheus/client_golang/prometheus"
)
const metricNamespace = "libp2p_relaysvc"
var (
status = prometheus .NewGauge (
prometheus .GaugeOpts {
Namespace : metricNamespace ,
Name : "status" ,
Help : "Relay Status" ,
},
)
reservationsTotal = prometheus .NewCounterVec (
prometheus .CounterOpts {
Namespace : metricNamespace ,
Name : "reservations_total" ,
Help : "Relay Reservation Request" ,
},
[]string {"type" },
)
reservationRequestResponseStatusTotal = prometheus .NewCounterVec (
prometheus .CounterOpts {
Namespace : metricNamespace ,
Name : "reservation_request_response_status_total" ,
Help : "Relay Reservation Request Response Status" ,
},
[]string {"status" },
)
reservationRejectionsTotal = prometheus .NewCounterVec (
prometheus .CounterOpts {
Namespace : metricNamespace ,
Name : "reservation_rejections_total" ,
Help : "Relay Reservation Rejected Reason" ,
},
[]string {"reason" },
)
connectionsTotal = prometheus .NewCounterVec (
prometheus .CounterOpts {
Namespace : metricNamespace ,
Name : "connections_total" ,
Help : "Relay Connection Total" ,
},
[]string {"type" },
)
connectionRequestResponseStatusTotal = prometheus .NewCounterVec (
prometheus .CounterOpts {
Namespace : metricNamespace ,
Name : "connection_request_response_status_total" ,
Help : "Relay Connection Request Status" ,
},
[]string {"status" },
)
connectionRejectionsTotal = prometheus .NewCounterVec (
prometheus .CounterOpts {
Namespace : metricNamespace ,
Name : "connection_rejections_total" ,
Help : "Relay Connection Rejected Reason" ,
},
[]string {"reason" },
)
connectionDurationSeconds = prometheus .NewHistogram (
prometheus .HistogramOpts {
Namespace : metricNamespace ,
Name : "connection_duration_seconds" ,
Help : "Relay Connection Duration" ,
},
)
dataTransferredBytesTotal = prometheus .NewCounter (
prometheus .CounterOpts {
Namespace : metricNamespace ,
Name : "data_transferred_bytes_total" ,
Help : "Bytes Transferred Total" ,
},
)
collectors = []prometheus .Collector {
status ,
reservationsTotal ,
reservationRequestResponseStatusTotal ,
reservationRejectionsTotal ,
connectionsTotal ,
connectionRequestResponseStatusTotal ,
connectionRejectionsTotal ,
connectionDurationSeconds ,
dataTransferredBytesTotal ,
}
)
const (
requestStatusOK = "ok"
requestStatusRejected = "rejected"
requestStatusError = "error"
)
type MetricsTracer interface {
RelayStatus (enabled bool )
ConnectionOpened ()
ConnectionClosed (d time .Duration )
ConnectionRequestHandled (status pbv2 .Status )
ReservationAllowed (isRenewal bool )
ReservationClosed (cnt int )
ReservationRequestHandled (status pbv2 .Status )
BytesTransferred (cnt int )
}
type metricsTracer struct {}
var _ MetricsTracer = &metricsTracer {}
type metricsTracerSetting struct {
reg prometheus .Registerer
}
type MetricsTracerOption func (*metricsTracerSetting )
func WithRegisterer (reg prometheus .Registerer ) MetricsTracerOption {
return func (s *metricsTracerSetting ) {
if reg != nil {
s .reg = reg
}
}
}
func NewMetricsTracer (opts ...MetricsTracerOption ) MetricsTracer {
setting := &metricsTracerSetting {reg : prometheus .DefaultRegisterer }
for _ , opt := range opts {
opt (setting )
}
metricshelper .RegisterCollectors (setting .reg , collectors ...)
return &metricsTracer {}
}
func (mt *metricsTracer ) RelayStatus (enabled bool ) {
if enabled {
status .Set (1 )
} else {
status .Set (0 )
}
}
func (mt *metricsTracer ) ConnectionOpened () {
tags := metricshelper .GetStringSlice ()
defer metricshelper .PutStringSlice (tags )
*tags = append (*tags , "opened" )
connectionsTotal .WithLabelValues (*tags ...).Add (1 )
}
func (mt *metricsTracer ) ConnectionClosed (d time .Duration ) {
tags := metricshelper .GetStringSlice ()
defer metricshelper .PutStringSlice (tags )
*tags = append (*tags , "closed" )
connectionsTotal .WithLabelValues (*tags ...).Add (1 )
connectionDurationSeconds .Observe (d .Seconds ())
}
func (mt *metricsTracer ) ConnectionRequestHandled (status pbv2 .Status ) {
tags := metricshelper .GetStringSlice ()
defer metricshelper .PutStringSlice (tags )
respStatus := getResponseStatus (status )
*tags = append (*tags , respStatus )
connectionRequestResponseStatusTotal .WithLabelValues (*tags ...).Add (1 )
if respStatus == requestStatusRejected {
*tags = (*tags )[:0 ]
*tags = append (*tags , getRejectionReason (status ))
connectionRejectionsTotal .WithLabelValues (*tags ...).Add (1 )
}
}
func (mt *metricsTracer ) ReservationAllowed (isRenewal bool ) {
tags := metricshelper .GetStringSlice ()
defer metricshelper .PutStringSlice (tags )
if isRenewal {
*tags = append (*tags , "renewed" )
} else {
*tags = append (*tags , "opened" )
}
reservationsTotal .WithLabelValues (*tags ...).Add (1 )
}
func (mt *metricsTracer ) ReservationClosed (cnt int ) {
tags := metricshelper .GetStringSlice ()
defer metricshelper .PutStringSlice (tags )
*tags = append (*tags , "closed" )
reservationsTotal .WithLabelValues (*tags ...).Add (float64 (cnt ))
}
func (mt *metricsTracer ) ReservationRequestHandled (status pbv2 .Status ) {
tags := metricshelper .GetStringSlice ()
defer metricshelper .PutStringSlice (tags )
respStatus := getResponseStatus (status )
*tags = append (*tags , respStatus )
reservationRequestResponseStatusTotal .WithLabelValues (*tags ...).Add (1 )
if respStatus == requestStatusRejected {
*tags = (*tags )[:0 ]
*tags = append (*tags , getRejectionReason (status ))
reservationRejectionsTotal .WithLabelValues (*tags ...).Add (1 )
}
}
func (mt *metricsTracer ) BytesTransferred (cnt int ) {
dataTransferredBytesTotal .Add (float64 (cnt ))
}
func getResponseStatus(status pbv2 .Status ) string {
responseStatus := "unknown"
switch status {
case pbv2 .Status_RESERVATION_REFUSED ,
pbv2 .Status_RESOURCE_LIMIT_EXCEEDED ,
pbv2 .Status_PERMISSION_DENIED ,
pbv2 .Status_NO_RESERVATION ,
pbv2 .Status_MALFORMED_MESSAGE :
responseStatus = requestStatusRejected
case pbv2 .Status_UNEXPECTED_MESSAGE , pbv2 .Status_CONNECTION_FAILED :
responseStatus = requestStatusError
case pbv2 .Status_OK :
responseStatus = requestStatusOK
}
return responseStatus
}
func getRejectionReason(status pbv2 .Status ) string {
reason := "unknown"
switch status {
case pbv2 .Status_RESERVATION_REFUSED :
reason = "ip constraint violation"
case pbv2 .Status_RESOURCE_LIMIT_EXCEEDED :
reason = "resource limit exceeded"
case pbv2 .Status_PERMISSION_DENIED :
reason = "permission denied"
case pbv2 .Status_NO_RESERVATION :
reason = "no reservation"
case pbv2 .Status_MALFORMED_MESSAGE :
reason = "malformed message"
}
return reason
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .