github.com/XiaoMi/Gaea@v1.2.5/stats/prometheus/prometheus_backend.go (about) 1 package prometheus 2 3 import ( 4 "expvar" 5 "net/http" 6 "strings" 7 8 "github.com/prometheus/client_golang/prometheus" 9 "github.com/prometheus/client_golang/prometheus/promhttp" 10 "github.com/XiaoMi/Gaea/log" 11 "github.com/XiaoMi/Gaea/stats" 12 ) 13 14 // PromBackend implements PullBackend using Prometheus as the backing metrics storage. 15 type PromBackend struct { 16 namespace string 17 } 18 19 var ( 20 be PromBackend 21 ) 22 23 // Init initializes the Prometheus be with the given namespace. 24 func Init(namespace string) { 25 be.namespace = namespace 26 stats.Register(be.publishPrometheusMetric) 27 } 28 29 // GetHandlers return registered handlers 30 func GetHandlers() map[string]http.Handler { 31 return map[string]http.Handler{ 32 "/metrics": promhttp.Handler(), 33 } 34 } 35 36 // PublishPromMetric is used to publish the metric to Prometheus. 37 func (be PromBackend) publishPrometheusMetric(name string, v expvar.Var) { 38 switch st := v.(type) { 39 case *stats.Counter: 40 newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.Get()) }) 41 case *stats.CounterFunc: 42 newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.F()) }) 43 case *stats.Gauge: 44 newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.Get()) }) 45 case *stats.GaugeFunc: 46 newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.F()) }) 47 case *stats.CountersWithSingleLabel: 48 newCountersWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.CounterValue) 49 case *stats.CountersWithMultiLabels: 50 newMetricWithMultiLabelsCollector(st, be.buildPromName(name)) 51 case *stats.CountersFuncWithMultiLabels: 52 newMetricsFuncWithMultiLabelsCollector(st, be.buildPromName(name), prometheus.CounterValue) 53 case *stats.GaugesFuncWithMultiLabels: 54 newMetricsFuncWithMultiLabelsCollector(&st.CountersFuncWithMultiLabels, be.buildPromName(name), prometheus.GaugeValue) 55 case *stats.GaugesWithSingleLabel: 56 newGaugesWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.GaugeValue) 57 case *stats.GaugesWithMultiLabels: 58 newGaugesWithMultiLabelsCollector(st, be.buildPromName(name)) 59 case *stats.CounterDuration: 60 newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.Get().Seconds() }) 61 case *stats.CounterDurationFunc: 62 newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.F().Seconds() }) 63 case *stats.GaugeDuration: 64 newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.Get().Seconds() }) 65 case *stats.GaugeDurationFunc: 66 newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.F().Seconds() }) 67 case *stats.Timings: 68 newTimingsCollector(st, be.buildPromName(name)) 69 case *stats.MultiTimings: 70 newMultiTimingsCollector(st, be.buildPromName(name)) 71 case *stats.Histogram: 72 newHistogramCollector(st, be.buildPromName(name)) 73 default: 74 log.Warn("[prometheus] Not exporting to Prometheus an unsupported metric type of %T: %s", st, name) 75 } 76 } 77 78 // buildPromName specifies the namespace as a prefix to the metric name 79 func (be PromBackend) buildPromName(name string) string { 80 s := strings.TrimPrefix(normalizeMetric(name), be.namespace+"_") 81 return prometheus.BuildFQName("", be.namespace, s) 82 } 83 84 func labelsToSnake(labels []string) []string { 85 output := make([]string, len(labels)) 86 for i, l := range labels { 87 output[i] = normalizeMetric(l) 88 } 89 return output 90 } 91 92 // normalizeMetricForPrometheus produces a compliant name by applying 93 // special case conversions and then applying a camel case to snake case converter. 94 func normalizeMetric(name string) string { 95 // Special cases 96 r := strings.NewReplacer("VSchema", "vschema", "VtGate", "vtgate") 97 name = r.Replace(name) 98 99 return stats.GetSnakeName(name) 100 }