prometheusbackend.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. Copyright 2019 The Vitess Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package prometheusbackend
  14. import (
  15. "expvar"
  16. "strings"
  17. "github.com/prometheus/client_golang/prometheus"
  18. "git.nspix.com/golang/micro/stats"
  19. )
  20. // PromBackend implements PullBackend using Prometheus as the backing metrics storage.
  21. type PromBackend struct {
  22. namespace string
  23. }
  24. var (
  25. be PromBackend
  26. )
  27. // Init initializes the Prometheus be with the given namespace.
  28. func Init(namespace string) {
  29. be.namespace = namespace
  30. stats.Register(be.publishPrometheusMetric)
  31. }
  32. // PublishPromMetric is used to publish the metric to Prometheus.
  33. func (be PromBackend) publishPrometheusMetric(name string, v expvar.Var) {
  34. switch st := v.(type) {
  35. case *stats.Counter:
  36. newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.Get()) })
  37. case *stats.CounterFunc:
  38. newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.F()) })
  39. case *stats.Gauge:
  40. newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.Get()) })
  41. case *stats.GaugeFunc:
  42. newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.F()) })
  43. case stats.FloatFunc:
  44. newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return (st)() })
  45. case *stats.CountersWithSingleLabel:
  46. newCountersWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.CounterValue)
  47. case *stats.CountersWithMultiLabels:
  48. newMetricWithMultiLabelsCollector(st, be.buildPromName(name))
  49. case *stats.CountersFuncWithMultiLabels:
  50. newMetricsFuncWithMultiLabelsCollector(st, be.buildPromName(name), prometheus.CounterValue)
  51. case *stats.GaugesFuncWithMultiLabels:
  52. newMetricsFuncWithMultiLabelsCollector(&st.CountersFuncWithMultiLabels, be.buildPromName(name), prometheus.GaugeValue)
  53. case *stats.GaugesWithSingleLabel:
  54. newGaugesWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.GaugeValue)
  55. case *stats.GaugesWithMultiLabels:
  56. newGaugesWithMultiLabelsCollector(st, be.buildPromName(name))
  57. case *stats.CounterDuration:
  58. newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.Get().Seconds() })
  59. case *stats.CounterDurationFunc:
  60. newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.F().Seconds() })
  61. case *stats.GaugeDuration:
  62. newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.Get().Seconds() })
  63. case *stats.GaugeDurationFunc:
  64. newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.F().Seconds() })
  65. case *stats.Timings:
  66. newTimingsCollector(st, be.buildPromName(name))
  67. case *stats.MultiTimings:
  68. newMultiTimingsCollector(st, be.buildPromName(name))
  69. case *stats.Histogram:
  70. newHistogramCollector(st, be.buildPromName(name))
  71. case *stats.String, stats.StringFunc, stats.StringMapFunc, *stats.Rates, *stats.RatesFunc:
  72. // Silently ignore these types since they don't make sense to
  73. // export to Prometheus' data model.
  74. default:
  75. }
  76. }
  77. // buildPromName specifies the namespace as a prefix to the metric name
  78. func (be PromBackend) buildPromName(name string) string {
  79. s := strings.TrimPrefix(normalizeMetric(name), be.namespace+"_")
  80. return prometheus.BuildFQName("", be.namespace, s)
  81. }
  82. func labelsToSnake(labels []string) []string {
  83. output := make([]string, len(labels))
  84. for i, l := range labels {
  85. output[i] = normalizeMetric(l)
  86. }
  87. return output
  88. }
  89. // normalizeMetricForPrometheus produces a compliant name by applying
  90. // special case conversions and then applying a camel case to snake case converter.
  91. func normalizeMetric(name string) string {
  92. // Special cases
  93. r := strings.NewReplacer("VSchema", "vschema", "VtGate", "vtgate")
  94. name = r.Replace(name)
  95. return stats.GetSnakeName(name)
  96. }