github.com/vipernet-xyz/tm@v0.34.24/p2p/metrics.go (about)

     1  package p2p
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"regexp"
     7  	"sync"
     8  
     9  	"github.com/go-kit/kit/metrics"
    10  	"github.com/go-kit/kit/metrics/discard"
    11  	"github.com/go-kit/kit/metrics/prometheus"
    12  	stdprometheus "github.com/prometheus/client_golang/prometheus"
    13  )
    14  
    15  const (
    16  	// MetricsSubsystem is a subsystem shared by all metrics exposed by this
    17  	// package.
    18  	MetricsSubsystem = "p2p"
    19  )
    20  
    21  var (
    22  	// valueToLabelRegexp is used to find the golang package name and type name
    23  	// so that the name can be turned into a prometheus label where the characters
    24  	// in the label do not include prometheus special characters such as '*' and '.'.
    25  	valueToLabelRegexp = regexp.MustCompile(`\*?(\w+)\.(.*)`)
    26  )
    27  
    28  // Metrics contains metrics exposed by this package.
    29  type Metrics struct {
    30  	// Number of peers.
    31  	Peers metrics.Gauge
    32  	// Number of bytes received from a given peer.
    33  	PeerReceiveBytesTotal metrics.Counter
    34  	// Number of bytes sent to a given peer.
    35  	PeerSendBytesTotal metrics.Counter
    36  	// Pending bytes to be sent to a given peer.
    37  	PeerPendingSendBytes metrics.Gauge
    38  	// Number of transactions submitted by each peer.
    39  	NumTxs metrics.Gauge
    40  	// Number of bytes of each message type received.
    41  	MessageReceiveBytesTotal metrics.Counter
    42  	// Number of bytes of each message type sent.
    43  	MessageSendBytesTotal metrics.Counter
    44  }
    45  
    46  // PrometheusMetrics returns Metrics build using Prometheus client library.
    47  // Optionally, labels can be provided along with their values ("foo",
    48  // "fooValue").
    49  func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
    50  	labels := []string{}
    51  	for i := 0; i < len(labelsAndValues); i += 2 {
    52  		labels = append(labels, labelsAndValues[i])
    53  	}
    54  	return &Metrics{
    55  		Peers: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
    56  			Namespace: namespace,
    57  			Subsystem: MetricsSubsystem,
    58  			Name:      "peers",
    59  			Help:      "Number of peers.",
    60  		}, labels).With(labelsAndValues...),
    61  		PeerReceiveBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    62  			Namespace: namespace,
    63  			Subsystem: MetricsSubsystem,
    64  			Name:      "peer_receive_bytes_total",
    65  			Help:      "Number of bytes received from a given peer.",
    66  		}, append(labels, "peer_id", "chID")).With(labelsAndValues...),
    67  		PeerSendBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    68  			Namespace: namespace,
    69  			Subsystem: MetricsSubsystem,
    70  			Name:      "peer_send_bytes_total",
    71  			Help:      "Number of bytes sent to a given peer.",
    72  		}, append(labels, "peer_id", "chID")).With(labelsAndValues...),
    73  		PeerPendingSendBytes: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
    74  			Namespace: namespace,
    75  			Subsystem: MetricsSubsystem,
    76  			Name:      "peer_pending_send_bytes",
    77  			Help:      "Pending bytes to be sent to a given peer.",
    78  		}, append(labels, "peer_id")).With(labelsAndValues...),
    79  		NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
    80  			Namespace: namespace,
    81  			Subsystem: MetricsSubsystem,
    82  			Name:      "num_txs",
    83  			Help:      "Number of transactions submitted by each peer.",
    84  		}, append(labels, "peer_id")).With(labelsAndValues...),
    85  		MessageReceiveBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    86  			Namespace: namespace,
    87  			Subsystem: MetricsSubsystem,
    88  			Name:      "message_receive_bytes_total",
    89  			Help:      "Number of bytes of each message type received.",
    90  		}, append(labels, "message_type")).With(labelsAndValues...),
    91  		MessageSendBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    92  			Namespace: namespace,
    93  			Subsystem: MetricsSubsystem,
    94  			Name:      "message_send_bytes_total",
    95  			Help:      "Number of bytes of each message type sent.",
    96  		}, append(labels, "message_type")).With(labelsAndValues...),
    97  	}
    98  }
    99  
   100  func NopMetrics() *Metrics {
   101  	return &Metrics{
   102  		Peers:                    discard.NewGauge(),
   103  		PeerReceiveBytesTotal:    discard.NewCounter(),
   104  		PeerSendBytesTotal:       discard.NewCounter(),
   105  		PeerPendingSendBytes:     discard.NewGauge(),
   106  		NumTxs:                   discard.NewGauge(),
   107  		MessageReceiveBytesTotal: discard.NewCounter(),
   108  		MessageSendBytesTotal:    discard.NewCounter(),
   109  	}
   110  }
   111  
   112  type metricsLabelCache struct {
   113  	mtx               *sync.RWMutex
   114  	messageLabelNames map[reflect.Type]string
   115  }
   116  
   117  // ValueToMetricLabel is a method that is used to produce a prometheus label value of the golang
   118  // type that is passed in.
   119  // This method uses a map on the Metrics struct so that each label name only needs
   120  // to be produced once to prevent expensive string operations.
   121  func (m *metricsLabelCache) ValueToMetricLabel(i interface{}) string {
   122  	t := reflect.TypeOf(i)
   123  	m.mtx.RLock()
   124  
   125  	if s, ok := m.messageLabelNames[t]; ok {
   126  		m.mtx.RUnlock()
   127  		return s
   128  	}
   129  	m.mtx.RUnlock()
   130  
   131  	s := t.String()
   132  	ss := valueToLabelRegexp.FindStringSubmatch(s)
   133  	l := fmt.Sprintf("%s_%s", ss[1], ss[2])
   134  	m.mtx.Lock()
   135  	defer m.mtx.Unlock()
   136  	m.messageLabelNames[t] = l
   137  	return l
   138  }
   139  
   140  func newMetricsLabelCache() *metricsLabelCache {
   141  	return &metricsLabelCache{
   142  		mtx:               &sync.RWMutex{},
   143  		messageLabelNames: map[reflect.Type]string{},
   144  	}
   145  }