package autonat import ( "time" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/p2p/host/autonat/pb" "github.com/libp2p/go-libp2p/p2p/metricshelper" "github.com/prometheus/client_golang/prometheus" ) const metricNamespace = "libp2p_autonat" var ( reachabilityStatus = prometheus.NewGauge( prometheus.GaugeOpts{ Namespace: metricNamespace, Name: "reachability_status", Help: "Current node reachability", }, ) reachabilityStatusConfidence = prometheus.NewGauge( prometheus.GaugeOpts{ Namespace: metricNamespace, Name: "reachability_status_confidence", Help: "Node reachability status confidence", }, ) receivedDialResponseTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, Name: "received_dial_response_total", Help: "Count of dial responses for client", }, []string{"response_status"}, ) outgoingDialResponseTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, Name: "outgoing_dial_response_total", Help: "Count of dial responses for server", }, []string{"response_status"}, ) outgoingDialRefusedTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: metricNamespace, Name: "outgoing_dial_refused_total", Help: "Count of dial requests refused by server", }, []string{"refusal_reason"}, ) nextProbeTimestamp = prometheus.NewGauge( prometheus.GaugeOpts{ Namespace: metricNamespace, Name: "next_probe_timestamp", Help: "Time of next probe", }, ) collectors = []prometheus.Collector{ reachabilityStatus, reachabilityStatusConfidence, receivedDialResponseTotal, outgoingDialResponseTotal, outgoingDialRefusedTotal, nextProbeTimestamp, } ) type MetricsTracer interface { ReachabilityStatus(status network.Reachability) ReachabilityStatusConfidence(confidence int) ReceivedDialResponse(status pb.Message_ResponseStatus) OutgoingDialResponse(status pb.Message_ResponseStatus) OutgoingDialRefused(reason string) NextProbeTime(t time.Time) } func getResponseStatus(status pb.Message_ResponseStatus) string { var s string switch status { case pb.Message_OK: s = "ok" case pb.Message_E_DIAL_ERROR: s = "dial error" case pb.Message_E_DIAL_REFUSED: s = "dial refused" case pb.Message_E_BAD_REQUEST: s = "bad request" case pb.Message_E_INTERNAL_ERROR: s = "internal error" default: s = "unknown" } return s } const ( rate_limited = "rate limited" dial_blocked = "dial blocked" no_valid_address = "no valid address" ) 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) ReachabilityStatus(status network.Reachability) { reachabilityStatus.Set(float64(status)) } func (mt *metricsTracer) ReachabilityStatusConfidence(confidence int) { reachabilityStatusConfidence.Set(float64(confidence)) } func (mt *metricsTracer) ReceivedDialResponse(status pb.Message_ResponseStatus) { tags := metricshelper.GetStringSlice() *tags = append(*tags, getResponseStatus(status)) receivedDialResponseTotal.WithLabelValues(*tags...).Inc() metricshelper.PutStringSlice(tags) } func (mt *metricsTracer) OutgoingDialResponse(status pb.Message_ResponseStatus) { tags := metricshelper.GetStringSlice() *tags = append(*tags, getResponseStatus(status)) outgoingDialResponseTotal.WithLabelValues(*tags...).Inc() metricshelper.PutStringSlice(tags) } func (mt *metricsTracer) OutgoingDialRefused(reason string) { tags := metricshelper.GetStringSlice() *tags = append(*tags, reason) outgoingDialRefusedTotal.WithLabelValues(*tags...).Inc() metricshelper.PutStringSlice(tags) } func (mt *metricsTracer) NextProbeTime(t time.Time) { nextProbeTimestamp.Set(float64(t.Unix())) }