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  }