Package list golang-github-go-kit-kit / a1d8b3f
metrics: add callback constructors for Gauges Gauges may be more efficiently used in application code via a callback mechanism, rather than explicit Set/Add invocations. Peter Bourgon 6 years ago
3 changed file(s) with 71 addition(s) and 16 deletion(s). Raw diff Collapse all Expand all
1818 import (
1919 "expvar"
2020 "fmt"
21 "strconv"
2122 "sync"
2223 "time"
2324
3738 }
3839
3940 func (c *counter) With(metrics.Field) metrics.Counter { return c }
40
41 func (c *counter) Add(delta uint64) { c.v.Add(int64(delta)) }
41 func (c *counter) Add(delta uint64) { c.v.Add(int64(delta)) }
4242
4343 type gauge struct {
4444 v *expvar.Float
4545 }
4646
47 // NewGauge returns a new Gauge backed by an expvar with the given name.
48 // Fields are ignored.
47 // NewGauge returns a new Gauge backed by an expvar with the given name. It
48 // should be updated manually; for a callback-based approach, see
49 // NewCallbackGauge. Fields are ignored.
4950 func NewGauge(name string) metrics.Gauge {
5051 return &gauge{expvar.NewFloat(name)}
5152 }
5556 func (g *gauge) Add(delta float64) { g.v.Add(delta) }
5657
5758 func (g *gauge) Set(value float64) { g.v.Set(value) }
59
60 // PublishCallbackGauge publishes a Gauge as an expvar with the given name,
61 // whose value is determined at collect time by the passed callback function.
62 // The callback determines the value, and fields are ignored, so
63 // PublishCallbackGauge returns nothing.
64 func PublishCallbackGauge(name string, callback func() float64) {
65 expvar.Publish(name, callbackGauge(callback))
66 }
67
68 type callbackGauge func() float64
69
70 func (g callbackGauge) String() string { return strconv.FormatFloat(g(), 'g', -1, 64) }
5871
5972 type histogram struct {
6073 mu sync.Mutex
110110 g.GaugeVec.With(prometheus.Labels(g.Pairs)).Add(delta)
111111 }
112112
113 // RegisterCallbackGauge registers a Gauge with Prometheus whose value is
114 // determined at collect time by the passed callback function. The callback
115 // determines the value, and fields are ignored, so RegisterCallbackGauge
116 // returns nothing.
117 func RegisterCallbackGauge(namespace, subsystem, name, help string, callback func() float64) {
118 RegisterCallbackGaugeWithLabels(namespace, subsystem, name, help, prometheus.Labels{}, callback)
119 }
120
121 // RegisterCallbackGaugeWithLabels is the same as RegisterCallbackGauge, but
122 // attaches a set of const label pairs to the metric.
123 func RegisterCallbackGaugeWithLabels(namespace, subsystem, name, help string, constLabels prometheus.Labels, callback func() float64) {
124 prometheus.MustRegister(prometheus.NewGaugeFunc(
125 prometheus.GaugeOpts{
126 Namespace: namespace,
127 Subsystem: subsystem,
128 Name: name,
129 Help: help,
130 ConstLabels: constLabels,
131 },
132 callback,
133 ))
134 }
135
113136 type prometheusHistogram struct {
114137 *prometheus.SummaryVec
115138 Pairs map[string]string
2929 type statsdCounter chan string
3030
3131 // NewCounter returns a Counter that emits observations in the statsd protocol
32 // to the passed writer. Observations are buffered for the reporting interval
33 // or until the buffer exceeds a max packet size, whichever comes first.
34 // Fields are ignored.
32 // to the passed writer. Observations are buffered for the report interval or
33 // until the buffer exceeds a max packet size, whichever comes first. Fields
34 // are ignored.
3535 //
3636 // TODO: support for sampling.
37 func NewCounter(w io.Writer, key string, interval time.Duration) metrics.Counter {
37 func NewCounter(w io.Writer, key string, reportInterval time.Duration) metrics.Counter {
3838 c := make(chan string)
39 go fwd(w, key, interval, c)
39 go fwd(w, key, reportInterval, c)
4040 return statsdCounter(c)
4141 }
4242
4747 type statsdGauge chan string
4848
4949 // NewGauge returns a Gauge that emits values in the statsd protocol to the
50 // passed writer. Values are buffered for the reporting interval or until the
50 // passed writer. Values are buffered for the report interval or until the
5151 // buffer exceeds a max packet size, whichever comes first. Fields are
5252 // ignored.
5353 //
5454 // TODO: support for sampling.
55 func NewGauge(w io.Writer, key string, interval time.Duration) metrics.Gauge {
55 func NewGauge(w io.Writer, key string, reportInterval time.Duration) metrics.Gauge {
5656 g := make(chan string)
57 go fwd(w, key, interval, g)
57 go fwd(w, key, reportInterval, g)
5858 return statsdGauge(g)
5959 }
6060
7171
7272 func (g statsdGauge) Set(value float64) {
7373 g <- fmt.Sprintf("%f|g", value)
74 }
75
76 // NewCallbackGauge emits values in the statsd protocol to the passed writer.
77 // It collects values every scrape interval from the callback. Values are
78 // buffered for the report interval or until the buffer exceeds a max packet
79 // size, whichever comes first. The report and scrape intervals may be the
80 // same. Fields are ignored.
81 func NewCallbackGauge(w io.Writer, key string, reportInterval, scrapeInterval time.Duration, callback func() float64) {
82 go fwd(w, key, reportInterval, emitEvery(scrapeInterval, callback))
83 }
84
85 func emitEvery(d time.Duration, f func() float64) <-chan string {
86 c := make(chan string)
87 go func() {
88 for range time.Tick(d) {
89 c <- fmt.Sprintf("%f|g", f())
90 }
91 }()
92 return c
7493 }
7594
7695 type statsdHistogram chan string
92111 // NewTimeHistogram(statsdHistogram, time.Millisecond)
93112 //
94113 // TODO: support for sampling.
95 func NewHistogram(w io.Writer, key string, interval time.Duration) metrics.Histogram {
114 func NewHistogram(w io.Writer, key string, reportInterval time.Duration) metrics.Histogram {
96115 h := make(chan string)
97 go fwd(w, key, interval, h)
116 go fwd(w, key, reportInterval, h)
98117 return statsdHistogram(h)
99118 }
100119
106125
107126 var tick = time.Tick
108127
109 func fwd(w io.Writer, key string, interval time.Duration, c chan string) {
128 func fwd(w io.Writer, key string, reportInterval time.Duration, c <-chan string) {
110129 buf := &bytes.Buffer{}
111 tick := tick(interval)
130 tick := tick(reportInterval)
112131 for {
113132 select {
114133 case s := <-c: