1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
/*
Implements some additional prometheus metrics that we need for privacy preserving
counts of users and proxies
*/
package safeprom
import (
"sync/atomic"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"google.golang.org/protobuf/proto"
)
// New Prometheus counter type that produces rounded counts of metrics
// for privacy preserving reasons
type Counter interface {
prometheus.Metric
Inc()
}
type counter struct {
total uint64 //reflects the true count
value uint64 //reflects the rounded count
desc *prometheus.Desc
labelPairs []*dto.LabelPair
}
// Implements the Counter interface
func (c *counter) Inc() {
atomic.AddUint64(&c.total, 1)
if c.total > c.value {
atomic.AddUint64(&c.value, 8)
}
}
// Implements the prometheus.Metric interface
func (c *counter) Desc() *prometheus.Desc {
return c.desc
}
// Implements the prometheus.Metric interface
func (c *counter) Write(m *dto.Metric) error {
m.Label = c.labelPairs
m.Counter = &dto.Counter{Value: proto.Float64(float64(c.value))}
return nil
}
// New prometheus vector type that will track Counter metrics
// accross multiple labels
type CounterVec struct {
*prometheus.MetricVec
}
// NewCounterVec will create a CounterVec but will not register it, users must register it themselves.
// The behaviour of this function is similar to github.com/prometheus/client_golang/prometheus
func NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *CounterVec {
desc := prometheus.NewDesc(
prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.Help,
labelNames,
opts.ConstLabels,
)
c := &CounterVec{
MetricVec: prometheus.NewMetricVec(desc, func(lvs ...string) prometheus.Metric {
if len(lvs) != len(labelNames) {
panic("inconsistent cardinality")
}
return &counter{desc: desc, labelPairs: prometheus.MakeLabelPairs(desc, lvs)}
}),
}
return c
}
// NewCounterVecRegistered will create a CounterVec and register it.
// The behaviour of this function is similar to github.com/prometheus/client_golang/prometheus/promauto
func NewCounterVecRegistered(opts prometheus.CounterOpts, labelNames []string) *CounterVec {
c := NewCounterVec(opts, labelNames)
prometheus.DefaultRegisterer.MustRegister(c)
return c
}
// Helper function to return the underlying Counter metric from MetricVec
func (v *CounterVec) With(labels prometheus.Labels) Counter {
metric, err := v.GetMetricWith(labels)
if err != nil {
panic(err)
}
return metric.(Counter)
}
// Helper function to return the underlying Counter metric from MetricVec
func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
metric, err := v.GetMetricWithLabelValues(lvs...)
if err != nil {
panic(err)
}
return metric.(Counter)
}
|