github.com/Finschia/ostracon@v1.1.5/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  	// Added by Ostracon
    46  	// Number of abandoned peer messages
    47  	NumAbandonedPeerMsgs metrics.Counter
    48  	// Number of pooled peer messages
    49  	NumPooledPeerMsgs metrics.Gauge
    50  }
    51  
    52  // PrometheusMetrics returns Metrics build using Prometheus client library.
    53  // Optionally, labels can be provided along with their values ("foo",
    54  // "fooValue").
    55  func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
    56  	labels := []string{}
    57  	for i := 0; i < len(labelsAndValues); i += 2 {
    58  		labels = append(labels, labelsAndValues[i])
    59  	}
    60  	return &Metrics{
    61  		Peers: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
    62  			Namespace: namespace,
    63  			Subsystem: MetricsSubsystem,
    64  			Name:      "peers",
    65  			Help:      "Number of peers.",
    66  		}, labels).With(labelsAndValues...),
    67  		PeerReceiveBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    68  			Namespace: namespace,
    69  			Subsystem: MetricsSubsystem,
    70  			Name:      "peer_receive_bytes_total",
    71  			Help:      "Number of bytes received from a given peer.",
    72  		}, append(labels, "peer_id", "chID")).With(labelsAndValues...),
    73  		PeerSendBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    74  			Namespace: namespace,
    75  			Subsystem: MetricsSubsystem,
    76  			Name:      "peer_send_bytes_total",
    77  			Help:      "Number of bytes sent to a given peer.",
    78  		}, append(labels, "peer_id", "chID")).With(labelsAndValues...),
    79  		PeerPendingSendBytes: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
    80  			Namespace: namespace,
    81  			Subsystem: MetricsSubsystem,
    82  			Name:      "peer_pending_send_bytes",
    83  			Help:      "Pending bytes to be sent to a given peer.",
    84  		}, append(labels, "peer_id")).With(labelsAndValues...),
    85  		NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
    86  			Namespace: namespace,
    87  			Subsystem: MetricsSubsystem,
    88  			Name:      "num_txs",
    89  			Help:      "Number of transactions submitted by each peer.",
    90  		}, append(labels, "peer_id")).With(labelsAndValues...),
    91  		MessageReceiveBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    92  			Namespace: namespace,
    93  			Subsystem: MetricsSubsystem,
    94  			Name:      "message_receive_bytes_total",
    95  			Help:      "Number of bytes of each message type received.",
    96  		}, append(labels, "message_type")).With(labelsAndValues...),
    97  		MessageSendBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
    98  			Namespace: namespace,
    99  			Subsystem: MetricsSubsystem,
   100  			Name:      "message_send_bytes_total",
   101  			Help:      "Number of bytes of each message type sent.",
   102  		}, append(labels, "message_type")).With(labelsAndValues...),
   103  
   104  		// Added by Ostracon
   105  		NumAbandonedPeerMsgs: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
   106  			Namespace: namespace,
   107  			Subsystem: MetricsSubsystem,
   108  			Name:      "num_abandoned_peer_msgs",
   109  			Help:      "Number of peer messages abandoned because of full channel",
   110  		}, append(labels, "peer_id", "chID")).With(labelsAndValues...),
   111  		NumPooledPeerMsgs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
   112  			Namespace: namespace,
   113  			Subsystem: MetricsSubsystem,
   114  			Name:      "num_pooled_peer_msgs",
   115  			Help:      "Number of peer messages pooled currently",
   116  		}, append(labels, "peer_id", "chID")).With(labelsAndValues...),
   117  	}
   118  }
   119  
   120  func NopMetrics() *Metrics {
   121  	return &Metrics{
   122  		Peers:                    discard.NewGauge(),
   123  		PeerReceiveBytesTotal:    discard.NewCounter(),
   124  		PeerSendBytesTotal:       discard.NewCounter(),
   125  		PeerPendingSendBytes:     discard.NewGauge(),
   126  		NumTxs:                   discard.NewGauge(),
   127  		MessageReceiveBytesTotal: discard.NewCounter(),
   128  		MessageSendBytesTotal:    discard.NewCounter(),
   129  
   130  		// Added by Ostracon
   131  		NumAbandonedPeerMsgs: discard.NewCounter(),
   132  		NumPooledPeerMsgs:    discard.NewGauge(),
   133  	}
   134  }
   135  
   136  type metricsLabelCache struct {
   137  	mtx               *sync.RWMutex
   138  	messageLabelNames map[reflect.Type]string
   139  }
   140  
   141  // ValueToMetricLabel is a method that is used to produce a prometheus label value of the golang
   142  // type that is passed in.
   143  // This method uses a map on the Metrics struct so that each label name only needs
   144  // to be produced once to prevent expensive string operations.
   145  func (m *metricsLabelCache) ValueToMetricLabel(i interface{}) string {
   146  	t := reflect.TypeOf(i)
   147  	m.mtx.RLock()
   148  
   149  	if s, ok := m.messageLabelNames[t]; ok {
   150  		m.mtx.RUnlock()
   151  		return s
   152  	}
   153  	m.mtx.RUnlock()
   154  
   155  	s := t.String()
   156  	ss := valueToLabelRegexp.FindStringSubmatch(s)
   157  	l := fmt.Sprintf("%s_%s", ss[1], ss[2])
   158  	m.mtx.Lock()
   159  	defer m.mtx.Unlock()
   160  	m.messageLabelNames[t] = l
   161  	return l
   162  }
   163  
   164  func newMetricsLabelCache() *metricsLabelCache {
   165  	return &metricsLabelCache{
   166  		mtx:               &sync.RWMutex{},
   167  		messageLabelNames: map[reflect.Type]string{},
   168  	}
   169  }