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.

178 lines
6.4 KiB

7 years ago
7 years ago
7 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. func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
  55. labels := []string{}
  56. for i := 0; i < len(labelsAndValues); i += 2 {
  57. labels = append(labels, labelsAndValues[i])
  58. }
  59. return &Metrics{
  60. Peers: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
  61. Namespace: namespace,
  62. Subsystem: MetricsSubsystem,
  63. Name: "peers",
  64. Help: "Number of peers.",
  65. }, labels).With(labelsAndValues...),
  66. PeerReceiveBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
  67. Namespace: namespace,
  68. Subsystem: MetricsSubsystem,
  69. Name: "peer_receive_bytes_total",
  70. Help: "Number of bytes received from a given peer.",
  71. }, append(labels, "peer_id", "chID", "message_type")).With(labelsAndValues...),
  72. PeerSendBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
  73. Namespace: namespace,
  74. Subsystem: MetricsSubsystem,
  75. Name: "peer_send_bytes_total",
  76. Help: "Number of bytes sent to a given peer.",
  77. }, append(labels, "peer_id", "chID", "message_type")).With(labelsAndValues...),
  78. PeerPendingSendBytes: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
  79. Namespace: namespace,
  80. Subsystem: MetricsSubsystem,
  81. Name: "peer_pending_send_bytes",
  82. Help: "Number of pending bytes to be sent to a given peer.",
  83. }, append(labels, "peer_id")).With(labelsAndValues...),
  84. RouterPeerQueueRecv: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
  85. Namespace: namespace,
  86. Subsystem: MetricsSubsystem,
  87. Name: "router_peer_queue_recv",
  88. Help: "The time taken to read off of a peer's queue before sending on the connection.",
  89. }, labels).With(labelsAndValues...),
  90. RouterPeerQueueSend: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
  91. Namespace: namespace,
  92. Subsystem: MetricsSubsystem,
  93. Name: "router_peer_queue_send",
  94. Help: "The time taken to send on a peer's queue which will later be read and sent on the connection (see RouterPeerQueueRecv).",
  95. }, labels).With(labelsAndValues...),
  96. RouterChannelQueueSend: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
  97. Namespace: namespace,
  98. Subsystem: MetricsSubsystem,
  99. Name: "router_channel_queue_send",
  100. Help: "The time taken to send on a p2p channel's queue which will later be consued by the corresponding reactor/service.",
  101. }, labels).With(labelsAndValues...),
  102. PeerQueueDroppedMsgs: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
  103. Namespace: namespace,
  104. Subsystem: MetricsSubsystem,
  105. Name: "router_channel_queue_dropped_msgs",
  106. Help: "The number of messages dropped from a peer's queue for a specific p2p Channel.",
  107. }, append(labels, "ch_id")).With(labelsAndValues...),
  108. PeerQueueMsgSize: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
  109. Namespace: namespace,
  110. Subsystem: MetricsSubsystem,
  111. Name: "router_channel_queue_msg_size",
  112. Help: "The size of messages sent over a peer's queue for a specific p2p Channel.",
  113. }, append(labels, "ch_id")).With(labelsAndValues...),
  114. mtx: &sync.RWMutex{},
  115. messageLabelNames: map[reflect.Type]string{},
  116. }
  117. }
  118. // NopMetrics returns no-op Metrics.
  119. func NopMetrics() *Metrics {
  120. return &Metrics{
  121. Peers: discard.NewGauge(),
  122. PeerReceiveBytesTotal: discard.NewCounter(),
  123. PeerSendBytesTotal: discard.NewCounter(),
  124. PeerPendingSendBytes: discard.NewGauge(),
  125. RouterPeerQueueRecv: discard.NewHistogram(),
  126. RouterPeerQueueSend: discard.NewHistogram(),
  127. RouterChannelQueueSend: discard.NewHistogram(),
  128. PeerQueueDroppedMsgs: discard.NewCounter(),
  129. PeerQueueMsgSize: discard.NewGauge(),
  130. mtx: &sync.RWMutex{},
  131. messageLabelNames: map[reflect.Type]string{},
  132. }
  133. }
  134. // ValueToMetricLabel is a method that is used to produce a prometheus label value of the golang
  135. // type that is passed in.
  136. // This method uses a map on the Metrics struct so that each label name only needs
  137. // to be produced once to prevent expensive string operations.
  138. func (m *Metrics) ValueToMetricLabel(i interface{}) string {
  139. t := reflect.TypeOf(i)
  140. m.mtx.RLock()
  141. if s, ok := m.messageLabelNames[t]; ok {
  142. m.mtx.RUnlock()
  143. return s
  144. }
  145. m.mtx.RUnlock()
  146. s := t.String()
  147. ss := valueToLabelRegexp.FindStringSubmatch(s)
  148. l := fmt.Sprintf("%s_%s", ss[1], ss[2])
  149. m.mtx.Lock()
  150. defer m.mtx.Unlock()
  151. m.messageLabelNames[t] = l
  152. return l
  153. }