123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- /*
- Copyright 2019 The Vitess Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package prometheusbackend
- import (
- "expvar"
- "strings"
- "github.com/prometheus/client_golang/prometheus"
- "git.nspix.com/golang/micro/stats"
- )
- // PromBackend implements PullBackend using Prometheus as the backing metrics storage.
- type PromBackend struct {
- namespace string
- }
- var (
- be PromBackend
- )
- // Init initializes the Prometheus be with the given namespace.
- func Init(namespace string) {
- be.namespace = namespace
- stats.Register(be.publishPrometheusMetric)
- }
- // PublishPromMetric is used to publish the metric to Prometheus.
- func (be PromBackend) publishPrometheusMetric(name string, v expvar.Var) {
- switch st := v.(type) {
- case *stats.Counter:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.Get()) })
- case *stats.CounterFunc:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.F()) })
- case *stats.Gauge:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.Get()) })
- case *stats.GaugeFunc:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.F()) })
- case stats.FloatFunc:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return (st)() })
- case *stats.CountersWithSingleLabel:
- newCountersWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.CounterValue)
- case *stats.CountersWithMultiLabels:
- newMetricWithMultiLabelsCollector(st, be.buildPromName(name))
- case *stats.CountersFuncWithMultiLabels:
- newMetricsFuncWithMultiLabelsCollector(st, be.buildPromName(name), prometheus.CounterValue)
- case *stats.GaugesFuncWithMultiLabels:
- newMetricsFuncWithMultiLabelsCollector(&st.CountersFuncWithMultiLabels, be.buildPromName(name), prometheus.GaugeValue)
- case *stats.GaugesWithSingleLabel:
- newGaugesWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.GaugeValue)
- case *stats.GaugesWithMultiLabels:
- newGaugesWithMultiLabelsCollector(st, be.buildPromName(name))
- case *stats.CounterDuration:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.Get().Seconds() })
- case *stats.CounterDurationFunc:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.F().Seconds() })
- case *stats.GaugeDuration:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.Get().Seconds() })
- case *stats.GaugeDurationFunc:
- newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.F().Seconds() })
- case *stats.Timings:
- newTimingsCollector(st, be.buildPromName(name))
- case *stats.MultiTimings:
- newMultiTimingsCollector(st, be.buildPromName(name))
- case *stats.Histogram:
- newHistogramCollector(st, be.buildPromName(name))
- case *stats.String, stats.StringFunc, stats.StringMapFunc, *stats.Rates, *stats.RatesFunc:
- // Silently ignore these types since they don't make sense to
- // export to Prometheus' data model.
- default:
- }
- }
- // buildPromName specifies the namespace as a prefix to the metric name
- func (be PromBackend) buildPromName(name string) string {
- s := strings.TrimPrefix(normalizeMetric(name), be.namespace+"_")
- return prometheus.BuildFQName("", be.namespace, s)
- }
- func labelsToSnake(labels []string) []string {
- output := make([]string, len(labels))
- for i, l := range labels {
- output[i] = normalizeMetric(l)
- }
- return output
- }
- // normalizeMetricForPrometheus produces a compliant name by applying
- // special case conversions and then applying a camel case to snake case converter.
- func normalizeMetric(name string) string {
- // Special cases
- r := strings.NewReplacer("VSchema", "vschema", "VtGate", "vtgate")
- name = r.Replace(name)
- return stats.GetSnakeName(name)
- }
|