metrics.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package connection
  2. import (
  3. "sync"
  4. "github.com/prometheus/client_golang/prometheus"
  5. )
  6. const (
  7. MetricsNamespace = "cloudflared"
  8. TunnelSubsystem = "tunnel"
  9. muxerSubsystem = "muxer"
  10. configSubsystem = "config"
  11. )
  12. type localConfigMetrics struct {
  13. pushes prometheus.Counter
  14. pushesErrors prometheus.Counter
  15. }
  16. type tunnelMetrics struct {
  17. serverLocations *prometheus.GaugeVec
  18. // locationLock is a mutex for oldServerLocations
  19. locationLock sync.Mutex
  20. // oldServerLocations stores the last server the tunnel was connected to
  21. oldServerLocations map[string]string
  22. regSuccess *prometheus.CounterVec
  23. regFail *prometheus.CounterVec
  24. rpcFail *prometheus.CounterVec
  25. tunnelsHA tunnelsForHA
  26. userHostnamesCounts *prometheus.CounterVec
  27. localConfigMetrics *localConfigMetrics
  28. }
  29. func newLocalConfigMetrics() *localConfigMetrics {
  30. pushesMetric := prometheus.NewCounter(
  31. prometheus.CounterOpts{
  32. Namespace: MetricsNamespace,
  33. Subsystem: configSubsystem,
  34. Name: "local_config_pushes",
  35. Help: "Number of local configuration pushes to the edge",
  36. },
  37. )
  38. pushesErrorsMetric := prometheus.NewCounter(
  39. prometheus.CounterOpts{
  40. Namespace: MetricsNamespace,
  41. Subsystem: configSubsystem,
  42. Name: "local_config_pushes_errors",
  43. Help: "Number of errors occurred during local configuration pushes",
  44. },
  45. )
  46. prometheus.MustRegister(
  47. pushesMetric,
  48. pushesErrorsMetric,
  49. )
  50. return &localConfigMetrics{
  51. pushes: pushesMetric,
  52. pushesErrors: pushesErrorsMetric,
  53. }
  54. }
  55. // Metrics that can be collected without asking the edge
  56. func initTunnelMetrics() *tunnelMetrics {
  57. maxConcurrentRequestsPerTunnel := prometheus.NewGaugeVec(
  58. prometheus.GaugeOpts{
  59. Namespace: MetricsNamespace,
  60. Subsystem: TunnelSubsystem,
  61. Name: "max_concurrent_requests_per_tunnel",
  62. Help: "Largest number of concurrent requests proxied through each tunnel so far",
  63. },
  64. []string{"connection_id"},
  65. )
  66. prometheus.MustRegister(maxConcurrentRequestsPerTunnel)
  67. serverLocations := prometheus.NewGaugeVec(
  68. prometheus.GaugeOpts{
  69. Namespace: MetricsNamespace,
  70. Subsystem: TunnelSubsystem,
  71. Name: "server_locations",
  72. Help: "Where each tunnel is connected to. 1 means current location, 0 means previous locations.",
  73. },
  74. []string{"connection_id", "edge_location"},
  75. )
  76. prometheus.MustRegister(serverLocations)
  77. rpcFail := prometheus.NewCounterVec(
  78. prometheus.CounterOpts{
  79. Namespace: MetricsNamespace,
  80. Subsystem: TunnelSubsystem,
  81. Name: "tunnel_rpc_fail",
  82. Help: "Count of RPC connection errors by type",
  83. },
  84. []string{"error", "rpcName"},
  85. )
  86. prometheus.MustRegister(rpcFail)
  87. registerFail := prometheus.NewCounterVec(
  88. prometheus.CounterOpts{
  89. Namespace: MetricsNamespace,
  90. Subsystem: TunnelSubsystem,
  91. Name: "tunnel_register_fail",
  92. Help: "Count of tunnel registration errors by type",
  93. },
  94. []string{"error", "rpcName"},
  95. )
  96. prometheus.MustRegister(registerFail)
  97. userHostnamesCounts := prometheus.NewCounterVec(
  98. prometheus.CounterOpts{
  99. Namespace: MetricsNamespace,
  100. Subsystem: TunnelSubsystem,
  101. Name: "user_hostnames_counts",
  102. Help: "Which user hostnames cloudflared is serving",
  103. },
  104. []string{"userHostname"},
  105. )
  106. prometheus.MustRegister(userHostnamesCounts)
  107. registerSuccess := prometheus.NewCounterVec(
  108. prometheus.CounterOpts{
  109. Namespace: MetricsNamespace,
  110. Subsystem: TunnelSubsystem,
  111. Name: "tunnel_register_success",
  112. Help: "Count of successful tunnel registrations",
  113. },
  114. []string{"rpcName"},
  115. )
  116. prometheus.MustRegister(registerSuccess)
  117. return &tunnelMetrics{
  118. serverLocations: serverLocations,
  119. oldServerLocations: make(map[string]string),
  120. tunnelsHA: newTunnelsForHA(),
  121. regSuccess: registerSuccess,
  122. regFail: registerFail,
  123. rpcFail: rpcFail,
  124. userHostnamesCounts: userHostnamesCounts,
  125. localConfigMetrics: newLocalConfigMetrics(),
  126. }
  127. }
  128. func (t *tunnelMetrics) registerServerLocation(connectionID, loc string) {
  129. t.locationLock.Lock()
  130. defer t.locationLock.Unlock()
  131. if oldLoc, ok := t.oldServerLocations[connectionID]; ok && oldLoc == loc {
  132. return
  133. } else if ok {
  134. t.serverLocations.WithLabelValues(connectionID, oldLoc).Dec()
  135. }
  136. t.serverLocations.WithLabelValues(connectionID, loc).Inc()
  137. t.oldServerLocations[connectionID] = loc
  138. }
  139. var tunnelMetricsInternal struct {
  140. sync.Once
  141. metrics *tunnelMetrics
  142. }
  143. func newTunnelMetrics() *tunnelMetrics {
  144. tunnelMetricsInternal.Do(func() {
  145. tunnelMetricsInternal.metrics = initTunnelMetrics()
  146. })
  147. return tunnelMetricsInternal.metrics
  148. }