github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/promutil/wrapping.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package promutil 15 16 import ( 17 "github.com/pingcap/log" 18 "github.com/prometheus/client_golang/prometheus" 19 "go.uber.org/zap" 20 ) 21 22 // WrappingFactory uses inner Factory to create metrics and attaches some information 23 // to the metrics it created. 24 // The usage is dataflow engine can wrap prefix and labels for DM, and DM can wrap 25 // labels for dumpling/lightning. 26 type WrappingFactory struct { 27 inner Factory 28 prefix string 29 constLabels prometheus.Labels 30 } 31 32 // NewWrappingFactory creates a WrappingFactory. 33 // if `prefix` is not empty, it is added to the metric name to avoid cross app metric 34 // conflict, e.g. $prefix_$namespace_$subsystem_$name. 35 // `labels` is added to user metric when create metrics. 36 func NewWrappingFactory(f Factory, prefix string, labels prometheus.Labels) Factory { 37 return &WrappingFactory{ 38 inner: f, 39 prefix: prefix, 40 constLabels: labels, 41 } 42 } 43 44 // NewCounter works like the function of the same name in the prometheus package 45 // except for it will wrap prefix and constLabels. Thread-safe. 46 func (f *WrappingFactory) NewCounter(opts prometheus.CounterOpts) prometheus.Counter { 47 return f.inner.NewCounter(*wrapCounterOpts(f.prefix, f.constLabels, &opts)) 48 } 49 50 // NewCounterVec works like the function of the same name in the prometheus package 51 // except for it will wrap prefix and constLabels. Thread-safe. 52 func (f *WrappingFactory) NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec { 53 return f.inner.NewCounterVec(*wrapCounterOpts(f.prefix, f.constLabels, &opts), labelNames) 54 } 55 56 // NewGauge works like the function of the same name in the prometheus package 57 // except for it will wrap prefix and constLabels. Thread-safe. 58 func (f *WrappingFactory) NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge { 59 return f.inner.NewGauge(*wrapGaugeOpts(f.prefix, f.constLabels, &opts)) 60 } 61 62 // NewGaugeVec works like the function of the same name in the prometheus package 63 // except for it will wrap prefix and constLabels. Thread-safe. 64 func (f *WrappingFactory) NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec { 65 return f.inner.NewGaugeVec(*wrapGaugeOpts(f.prefix, f.constLabels, &opts), labelNames) 66 } 67 68 // NewHistogram works like the function of the same name in the prometheus package 69 // except for it will wrap prefix and constLabels. Thread-safe. 70 func (f *WrappingFactory) NewHistogram(opts prometheus.HistogramOpts) prometheus.Histogram { 71 return f.inner.NewHistogram(*wrapHistogramOpts(f.prefix, f.constLabels, &opts)) 72 } 73 74 // NewHistogramVec works like the function of the same name in the prometheus package 75 // except for it will wrap prefix and constLabels. Thread-safe. 76 func (f *WrappingFactory) NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec { 77 return f.inner.NewHistogramVec(*wrapHistogramOpts(f.prefix, f.constLabels, &opts), labelNames) 78 } 79 80 func wrapCounterOpts(prefix string, constLabels prometheus.Labels, opts *prometheus.CounterOpts) *prometheus.CounterOpts { 81 if opts.ConstLabels == nil && constLabels != nil { 82 opts.ConstLabels = make(prometheus.Labels) 83 } 84 wrapOptsCommon(prefix, constLabels, &opts.Namespace, opts.ConstLabels) 85 return opts 86 } 87 88 func wrapGaugeOpts(prefix string, constLabels prometheus.Labels, opts *prometheus.GaugeOpts) *prometheus.GaugeOpts { 89 if opts.ConstLabels == nil && constLabels != nil { 90 opts.ConstLabels = make(prometheus.Labels) 91 } 92 wrapOptsCommon(prefix, constLabels, &opts.Namespace, opts.ConstLabels) 93 return opts 94 } 95 96 func wrapHistogramOpts(prefix string, constLabels prometheus.Labels, opts *prometheus.HistogramOpts) *prometheus.HistogramOpts { 97 if opts.ConstLabels == nil && constLabels != nil { 98 opts.ConstLabels = make(prometheus.Labels) 99 } 100 wrapOptsCommon(prefix, constLabels, &opts.Namespace, opts.ConstLabels) 101 return opts 102 } 103 104 func wrapOptsCommon(prefix string, constLabels prometheus.Labels, namespace *string, cls prometheus.Labels) { 105 // namespace SHOULD NOT be nil 106 if prefix != "" { 107 if *namespace != "" { 108 *namespace = prefix + "_" + *namespace 109 } else { 110 *namespace = prefix 111 } 112 } 113 for name, value := range constLabels { 114 if _, exists := cls[name]; exists { 115 log.Panic("duplicate label name", zap.String("label", name)) 116 } 117 cls[name] = value 118 } 119 }