You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
6.4 KiB

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