package metric import ( "github.com/prometheus/client_golang/prometheus" "sync" ) const missVal = "MissLabel" // CounterVecDecorator Add safe decorator type CounterVecDecorator struct { *prometheus.CounterVec secureLabels []string once *sync.Once } func NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *CounterVecDecorator { v := &CounterVecDecorator{prometheus.NewCounterVec(opts, labelNames), labelNames, &sync.Once{}} return v } // With is secure wrap for with of prometheus.CounterVec // there is no panic, and always calculate to metrics , if miss values, will calculate to MissLabel // It's secure func (v *CounterVecDecorator) With(labels prometheus.Labels) prometheus.Counter { // To avoid initialization sequence, so must delay register to with func v.once.Do(func() { Register(v) }) safeLabels := labelAlignment(v.secureLabels, labels) // c, err := v.GetMetricWith(safeLabels) if err != nil { // should never happen , but should still add handler to record alert // TODO singleton alert Gauge and return an alert counter } return c } // GaugeVecDecorator Add safe decorator type GaugeVecDecorator struct { *prometheus.GaugeVec secureLabels []string once *sync.Once } func NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *GaugeVecDecorator { v := &GaugeVecDecorator{prometheus.NewGaugeVec(opts, labelNames), labelNames, &sync.Once{}} return v } // With is secure wrap for with of prometheus.GaugeVec // there is no panic, and always calculate to metrics , if miss values, will calculate to MissLabel // It's secure func (v *GaugeVecDecorator) With(labels prometheus.Labels) prometheus.Gauge { // To avoid initialization sequence, so must delay register to with func v.once.Do(func() { Register(v) }) safeLabels := labelAlignment(v.secureLabels, labels) // c, err := v.GetMetricWith(safeLabels) if err != nil { // should never happen , but should still add handler to record alert // TODO singleton alert Gauge and return } return c } // HistogramVecDecorator Add safe type HistogramVecDecorator struct { *prometheus.HistogramVec secureLabels []string once *sync.Once } func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *HistogramVecDecorator { v := &HistogramVecDecorator{prometheus.NewHistogramVec(opts, labelNames), labelNames, &sync.Once{}} return v } // With is secure wrap for with of prometheus.HistogramVec // there is no panic, and always calculate to metrics , if miss values, will calculate to MissLabel // It's secure func (v *HistogramVecDecorator) With(labels prometheus.Labels) prometheus.Observer { // To avoid initialization sequence, so must delay register to with func v.once.Do(func() { Register(v) }) safeLabels := labelAlignment(v.secureLabels, labels) // c, err := v.GetMetricWith(safeLabels) if err != nil { // should never happen , but should still add handler to record alert // TODO singleton alert Histogram and return } return c } // SummaryVecDecorator Add safe type SummaryVecDecorator struct { *prometheus.SummaryVec secureLabels []string once *sync.Once } func NewSummaryVec(opts prometheus.SummaryOpts, labelNames []string) *SummaryVecDecorator { v := &SummaryVecDecorator{prometheus.NewSummaryVec(opts, labelNames), labelNames, &sync.Once{}} //if len(autoReg) == 0 || autoReg[0] == true { // Register(v) //} return v } // With is secure wrap for with of prometheus.SummaryVec // there is no panic, and always calculate to metrics , if miss values, will calculate to MissLabel // It's secure func (v *SummaryVecDecorator) With(labels prometheus.Labels) prometheus.Observer { // To avoid initialization sequence, so must delay register to with func v.once.Do(func() { Register(v) }) safeLabels := labelAlignment(v.secureLabels, labels) // c, err := v.GetMetricWith(safeLabels) if err != nil { // should never happen , but should still add handler to record alert // TODO singleton alert Gauge and return } //prometheus.NewCounter(v.SummaryVec.) return c } // 标签对齐 func labelAlignment(labelNames []string, labels prometheus.Labels) prometheus.Labels { newLabels := make(prometheus.Labels, len(labelNames)) for _, val := range labelNames { if v, ok := labels[val]; ok { newLabels[val] = v } else { newLabels[val] = missVal } } return newLabels }