identify: add some basic metrics (#2069)

This commit is contained in:
Marten Seemann 2023-02-08 21:33:35 -08:00 committed by GitHub
parent a8d6111ba9
commit 5f8fe94f90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 500 additions and 20 deletions

View File

@ -230,12 +230,14 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
identify.UserAgent(opts.UserAgent),
identify.ProtocolVersion(opts.ProtocolVersion),
identify.DisableSignedPeerRecord(),
identify.WithMetricsTracer(identify.NewMetricsTracer()),
)
} else {
h.ids, err = identify.NewIDService(
h,
identify.UserAgent(opts.UserAgent),
identify.ProtocolVersion(opts.ProtocolVersion),
identify.WithMetricsTracer(identify.NewMetricsTracer()),
)
}
if err != nil {

View File

@ -8,8 +8,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
const metricNamespace = "libp2p_rcmgr"
var (
metricNamespace = "libp2p_rcmgr"
// Conns
conns = prometheus.NewGaugeVec(prometheus.GaugeOpts{

14
p2p/metricshelper/dir.go Normal file
View File

@ -0,0 +1,14 @@
package metricshelper
import "github.com/libp2p/go-libp2p/core/network"
func GetDirection(dir network.Direction) string {
switch dir {
case network.DirOutbound:
return "outbound"
case network.DirInbound:
return "inbound"
default:
return "unknown"
}
}

View File

@ -94,17 +94,6 @@ func NewMetricsTracer() *metricsTracer {
return &metricsTracer{}
}
func getDirection(dir network.Direction) string {
switch dir {
case network.DirOutbound:
return "outbound"
case network.DirInbound:
return "inbound"
default:
return "unknown"
}
}
func appendConnectionState(tags []string, cs network.ConnectionState) []string {
if cs.Transport == "" {
// This shouldn't happen, unless the transport doesn't properly set the Transport field in the ConnectionState.
@ -123,12 +112,12 @@ func (m *metricsTracer) OpenedConnection(dir network.Direction, p crypto.PubKey,
tags := metricshelper.GetStringSlice()
defer metricshelper.PutStringSlice(tags)
*tags = append(*tags, getDirection(dir))
*tags = append(*tags, metricshelper.GetDirection(dir))
*tags = appendConnectionState(*tags, cs)
connsOpened.WithLabelValues(*tags...).Inc()
*tags = (*tags)[:0]
*tags = append(*tags, getDirection(dir))
*tags = append(*tags, metricshelper.GetDirection(dir))
*tags = append(*tags, p.Type().String())
keyTypes.WithLabelValues(*tags...).Inc()
}
@ -137,12 +126,12 @@ func (m *metricsTracer) ClosedConnection(dir network.Direction, duration time.Du
tags := metricshelper.GetStringSlice()
defer metricshelper.PutStringSlice(tags)
*tags = append(*tags, getDirection(dir))
*tags = append(*tags, metricshelper.GetDirection(dir))
*tags = appendConnectionState(*tags, cs)
connsClosed.WithLabelValues(*tags...).Inc()
*tags = (*tags)[:0]
*tags = append(*tags, getDirection(dir))
*tags = append(*tags, metricshelper.GetDirection(dir))
*tags = appendConnectionState(*tags, cs)
connDuration.WithLabelValues(*tags...).Observe(duration.Seconds())
}

View File

@ -0,0 +1,355 @@
{
"__inputs": [
{
"name": "DS_PROMETHEUS",
"label": "Prometheus",
"description": "",
"type": "datasource",
"pluginId": "prometheus",
"pluginName": "Prometheus"
}
],
"__elements": {},
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "9.3.6"
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "1.0.0"
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "rate(libp2p_identify_identify_total[$__rate_interval])",
"legendFormat": "{{dir}}",
"range": true,
"refId": "A"
}
],
"title": "Identify Messages",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 5,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "rate(libp2p_identify_identify_push_total[$__rate_interval])",
"legendFormat": "{{dir}}",
"range": true,
"refId": "A"
}
],
"title": "Identify Push Messages",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 8
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "rate(libp2p_identify_identify_pushes_triggered_total[$__rate_interval])",
"legendFormat": "{{trigger}}",
"range": true,
"refId": "A"
}
],
"title": "Pushes triggered",
"type": "timeseries"
}
],
"schemaVersion": 37,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "libp2p Identify",
"uid": "0NDzQQ0Vz",
"version": 4,
"weekStart": ""
}

View File

@ -114,10 +114,11 @@ type idService struct {
UserAgent string
ProtocolVersion string
setupCompleted chan struct{} // is closed when Start has finished setting up
metricsTracer MetricsTracer
ctx context.Context
ctxCancel context.CancelFunc
setupCompleted chan struct{} // is closed when Start has finished setting up
ctx context.Context
ctxCancel context.CancelFunc
// track resources that need to be shut down before we shut down
refCount sync.WaitGroup
@ -176,6 +177,7 @@ func NewIDService(h host.Host, opts ...Option) (*idService, error) {
conns: make(map[network.Conn]entry),
disableSignedPeerRecord: cfg.disableSignedPeerRecord,
setupCompleted: make(chan struct{}),
metricsTracer: cfg.metricsTracer,
}
observedAddrs, err := NewObservedAddrManager(h)
@ -245,7 +247,13 @@ func (ids *idService) loop(ctx context.Context) {
for {
select {
case <-sub.Out():
case e, ok := <-sub.Out():
if !ok {
return
}
if ids.metricsTracer != nil {
ids.metricsTracer.TriggeredPushes(e)
}
ids.updateSnapshot()
select {
case triggerPush <- struct{}{}:
@ -299,6 +307,9 @@ func (ids *idService) sendPushes(ctx context.Context) {
if err != nil { // connection might have been closed recently
return
}
if ids.metricsTracer != nil {
ids.metricsTracer.IdentifyPush(network.DirOutbound)
}
// TODO: find out if the peer supports push if we didn't have any information about push support
if err := ids.sendIdentifyResp(str); err != nil {
log.Debugw("failed to send identify push", "peer", c.RemotePeer(), "error", err)
@ -390,15 +401,24 @@ func (ids *idService) identifyConn(c network.Conn) error {
return err
}
if ids.metricsTracer != nil {
ids.metricsTracer.Identify(network.DirInbound)
}
return ids.handleIdentifyResponse(s, false)
}
// handlePush handles incoming identify push streams
func (ids *idService) handlePush(s network.Stream) {
ids.handleIdentifyResponse(s, true)
if ids.metricsTracer != nil {
ids.metricsTracer.IdentifyPush(network.DirInbound)
}
}
func (ids *idService) handleIdentifyRequest(s network.Stream) {
if ids.metricsTracer != nil {
ids.metricsTracer.Identify(network.DirOutbound)
}
_ = ids.sendIdentifyResp(s)
}

View File

@ -0,0 +1,92 @@
package identify
import (
"sync"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/p2p/metricshelper"
"github.com/prometheus/client_golang/prometheus"
)
const metricNamespace = "libp2p_identify"
var (
pushesTriggered = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: metricNamespace,
Name: "identify_pushes_triggered_total",
Help: "Pushes Triggered",
},
[]string{"trigger"},
)
identify = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: metricNamespace,
Name: "identify_total",
Help: "Identify",
},
[]string{"dir"},
)
identifyPush = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: metricNamespace,
Name: "identify_push_total",
Help: "Identify Push",
},
[]string{"dir"},
)
)
var initMetricsOnce sync.Once
func initMetrics() {
prometheus.MustRegister(pushesTriggered, identify, identifyPush)
}
type MetricsTracer interface {
TriggeredPushes(event any)
Identify(network.Direction)
IdentifyPush(network.Direction)
}
type metricsTracer struct{}
var _ MetricsTracer = &metricsTracer{}
func NewMetricsTracer() MetricsTracer {
initMetricsOnce.Do(initMetrics)
return &metricsTracer{}
}
func (t *metricsTracer) TriggeredPushes(ev any) {
tags := metricshelper.GetStringSlice()
defer metricshelper.PutStringSlice(tags)
typ := "unknown"
switch ev.(type) {
case event.EvtLocalProtocolsUpdated:
typ = "protocols_updated"
case event.EvtLocalAddressesUpdated:
typ = "addresses_updated"
}
*tags = append(*tags, typ)
pushesTriggered.WithLabelValues(*tags...).Inc()
}
func (t *metricsTracer) Identify(dir network.Direction) {
tags := metricshelper.GetStringSlice()
defer metricshelper.PutStringSlice(tags)
*tags = append(*tags, metricshelper.GetDirection(dir))
identify.WithLabelValues(*tags...).Inc()
}
func (t *metricsTracer) IdentifyPush(dir network.Direction) {
tags := metricshelper.GetStringSlice()
defer metricshelper.PutStringSlice(tags)
*tags = append(*tags, metricshelper.GetDirection(dir))
identifyPush.WithLabelValues(*tags...).Inc()
}

View File

@ -4,6 +4,7 @@ type config struct {
protocolVersion string
userAgent string
disableSignedPeerRecord bool
metricsTracer MetricsTracer
}
// Option is an option function for identify.
@ -31,3 +32,9 @@ func DisableSignedPeerRecord() Option {
cfg.disableSignedPeerRecord = true
}
}
func WithMetricsTracer(tr MetricsTracer) Option {
return func(cfg *config) {
cfg.metricsTracer = tr
}
}