blob: a8e67228a45b0437ca415a0a48c1b9c9eb6ba34c [file] [log] [blame]
Scott Baker105df152020-04-13 15:55:14 -07001package metrics
2
3import (
4 "fmt"
5 "reflect"
6 "strings"
7 "sync"
8)
9
10// DuplicateMetric is the error returned by Registry.Register when a metric
11// already exists. If you mean to Register that metric you must first
12// Unregister the existing metric.
13type DuplicateMetric string
14
15func (err DuplicateMetric) Error() string {
16 return fmt.Sprintf("duplicate metric: %s", string(err))
17}
18
19// A Registry holds references to a set of metrics by name and can iterate
20// over them, calling callback functions provided by the user.
21//
22// This is an interface so as to encourage other structs to implement
23// the Registry API as appropriate.
24type Registry interface {
25
26 // Call the given function for each registered metric.
27 Each(func(string, interface{}))
28
29 // Get the metric by the given name or nil if none is registered.
30 Get(string) interface{}
31
32 // GetAll metrics in the Registry.
33 GetAll() map[string]map[string]interface{}
34
35 // Gets an existing metric or registers the given one.
36 // The interface can be the metric to register if not found in registry,
37 // or a function returning the metric for lazy instantiation.
38 GetOrRegister(string, interface{}) interface{}
39
40 // Register the given metric under the given name.
41 Register(string, interface{}) error
42
43 // Run all registered healthchecks.
44 RunHealthchecks()
45
46 // Unregister the metric with the given name.
47 Unregister(string)
48
49 // Unregister all metrics. (Mostly for testing.)
50 UnregisterAll()
51}
52
53// The standard implementation of a Registry is a mutex-protected map
54// of names to metrics.
55type StandardRegistry struct {
56 metrics map[string]interface{}
57 mutex sync.RWMutex
58}
59
60// Create a new registry.
61func NewRegistry() Registry {
62 return &StandardRegistry{metrics: make(map[string]interface{})}
63}
64
65// Call the given function for each registered metric.
66func (r *StandardRegistry) Each(f func(string, interface{})) {
67 metrics := r.registered()
68 for i := range metrics {
69 kv := &metrics[i]
70 f(kv.name, kv.value)
71 }
72}
73
74// Get the metric by the given name or nil if none is registered.
75func (r *StandardRegistry) Get(name string) interface{} {
76 r.mutex.RLock()
77 defer r.mutex.RUnlock()
78 return r.metrics[name]
79}
80
81// Gets an existing metric or creates and registers a new one. Threadsafe
82// alternative to calling Get and Register on failure.
83// The interface can be the metric to register if not found in registry,
84// or a function returning the metric for lazy instantiation.
85func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} {
86 // access the read lock first which should be re-entrant
87 r.mutex.RLock()
88 metric, ok := r.metrics[name]
89 r.mutex.RUnlock()
90 if ok {
91 return metric
92 }
93
94 // only take the write lock if we'll be modifying the metrics map
95 r.mutex.Lock()
96 defer r.mutex.Unlock()
97 if metric, ok := r.metrics[name]; ok {
98 return metric
99 }
100 if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
101 i = v.Call(nil)[0].Interface()
102 }
103 r.register(name, i)
104 return i
105}
106
107// Register the given metric under the given name. Returns a DuplicateMetric
108// if a metric by the given name is already registered.
109func (r *StandardRegistry) Register(name string, i interface{}) error {
110 r.mutex.Lock()
111 defer r.mutex.Unlock()
112 return r.register(name, i)
113}
114
115// Run all registered healthchecks.
116func (r *StandardRegistry) RunHealthchecks() {
117 r.mutex.RLock()
118 defer r.mutex.RUnlock()
119 for _, i := range r.metrics {
120 if h, ok := i.(Healthcheck); ok {
121 h.Check()
122 }
123 }
124}
125
126// GetAll metrics in the Registry
127func (r *StandardRegistry) GetAll() map[string]map[string]interface{} {
128 data := make(map[string]map[string]interface{})
129 r.Each(func(name string, i interface{}) {
130 values := make(map[string]interface{})
131 switch metric := i.(type) {
132 case Counter:
133 values["count"] = metric.Count()
134 case Gauge:
135 values["value"] = metric.Value()
136 case GaugeFloat64:
137 values["value"] = metric.Value()
138 case Healthcheck:
139 values["error"] = nil
140 metric.Check()
141 if err := metric.Error(); nil != err {
142 values["error"] = metric.Error().Error()
143 }
144 case Histogram:
145 h := metric.Snapshot()
146 ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
147 values["count"] = h.Count()
148 values["min"] = h.Min()
149 values["max"] = h.Max()
150 values["mean"] = h.Mean()
151 values["stddev"] = h.StdDev()
152 values["median"] = ps[0]
153 values["75%"] = ps[1]
154 values["95%"] = ps[2]
155 values["99%"] = ps[3]
156 values["99.9%"] = ps[4]
157 case Meter:
158 m := metric.Snapshot()
159 values["count"] = m.Count()
160 values["1m.rate"] = m.Rate1()
161 values["5m.rate"] = m.Rate5()
162 values["15m.rate"] = m.Rate15()
163 values["mean.rate"] = m.RateMean()
164 case Timer:
165 t := metric.Snapshot()
166 ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
167 values["count"] = t.Count()
168 values["min"] = t.Min()
169 values["max"] = t.Max()
170 values["mean"] = t.Mean()
171 values["stddev"] = t.StdDev()
172 values["median"] = ps[0]
173 values["75%"] = ps[1]
174 values["95%"] = ps[2]
175 values["99%"] = ps[3]
176 values["99.9%"] = ps[4]
177 values["1m.rate"] = t.Rate1()
178 values["5m.rate"] = t.Rate5()
179 values["15m.rate"] = t.Rate15()
180 values["mean.rate"] = t.RateMean()
181 }
182 data[name] = values
183 })
184 return data
185}
186
187// Unregister the metric with the given name.
188func (r *StandardRegistry) Unregister(name string) {
189 r.mutex.Lock()
190 defer r.mutex.Unlock()
191 r.stop(name)
192 delete(r.metrics, name)
193}
194
195// Unregister all metrics. (Mostly for testing.)
196func (r *StandardRegistry) UnregisterAll() {
197 r.mutex.Lock()
198 defer r.mutex.Unlock()
199 for name, _ := range r.metrics {
200 r.stop(name)
201 delete(r.metrics, name)
202 }
203}
204
205func (r *StandardRegistry) register(name string, i interface{}) error {
206 if _, ok := r.metrics[name]; ok {
207 return DuplicateMetric(name)
208 }
209 switch i.(type) {
210 case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer:
211 r.metrics[name] = i
212 }
213 return nil
214}
215
216type metricKV struct {
217 name string
218 value interface{}
219}
220
221func (r *StandardRegistry) registered() []metricKV {
222 r.mutex.RLock()
223 defer r.mutex.RUnlock()
224 metrics := make([]metricKV, 0, len(r.metrics))
225 for name, i := range r.metrics {
226 metrics = append(metrics, metricKV{
227 name: name,
228 value: i,
229 })
230 }
231 return metrics
232}
233
234func (r *StandardRegistry) stop(name string) {
235 if i, ok := r.metrics[name]; ok {
236 if s, ok := i.(Stoppable); ok {
237 s.Stop()
238 }
239 }
240}
241
242// Stoppable defines the metrics which has to be stopped.
243type Stoppable interface {
244 Stop()
245}
246
247type PrefixedRegistry struct {
248 underlying Registry
249 prefix string
250}
251
252func NewPrefixedRegistry(prefix string) Registry {
253 return &PrefixedRegistry{
254 underlying: NewRegistry(),
255 prefix: prefix,
256 }
257}
258
259func NewPrefixedChildRegistry(parent Registry, prefix string) Registry {
260 return &PrefixedRegistry{
261 underlying: parent,
262 prefix: prefix,
263 }
264}
265
266// Call the given function for each registered metric.
267func (r *PrefixedRegistry) Each(fn func(string, interface{})) {
268 wrappedFn := func(prefix string) func(string, interface{}) {
269 return func(name string, iface interface{}) {
270 if strings.HasPrefix(name, prefix) {
271 fn(name, iface)
272 } else {
273 return
274 }
275 }
276 }
277
278 baseRegistry, prefix := findPrefix(r, "")
279 baseRegistry.Each(wrappedFn(prefix))
280}
281
282func findPrefix(registry Registry, prefix string) (Registry, string) {
283 switch r := registry.(type) {
284 case *PrefixedRegistry:
285 return findPrefix(r.underlying, r.prefix+prefix)
286 case *StandardRegistry:
287 return r, prefix
288 }
289 return nil, ""
290}
291
292// Get the metric by the given name or nil if none is registered.
293func (r *PrefixedRegistry) Get(name string) interface{} {
294 realName := r.prefix + name
295 return r.underlying.Get(realName)
296}
297
298// Gets an existing metric or registers the given one.
299// The interface can be the metric to register if not found in registry,
300// or a function returning the metric for lazy instantiation.
301func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} {
302 realName := r.prefix + name
303 return r.underlying.GetOrRegister(realName, metric)
304}
305
306// Register the given metric under the given name. The name will be prefixed.
307func (r *PrefixedRegistry) Register(name string, metric interface{}) error {
308 realName := r.prefix + name
309 return r.underlying.Register(realName, metric)
310}
311
312// Run all registered healthchecks.
313func (r *PrefixedRegistry) RunHealthchecks() {
314 r.underlying.RunHealthchecks()
315}
316
317// GetAll metrics in the Registry
318func (r *PrefixedRegistry) GetAll() map[string]map[string]interface{} {
319 return r.underlying.GetAll()
320}
321
322// Unregister the metric with the given name. The name will be prefixed.
323func (r *PrefixedRegistry) Unregister(name string) {
324 realName := r.prefix + name
325 r.underlying.Unregister(realName)
326}
327
328// Unregister all metrics. (Mostly for testing.)
329func (r *PrefixedRegistry) UnregisterAll() {
330 r.underlying.UnregisterAll()
331}
332
333var DefaultRegistry Registry = NewRegistry()
334
335// Call the given function for each registered metric.
336func Each(f func(string, interface{})) {
337 DefaultRegistry.Each(f)
338}
339
340// Get the metric by the given name or nil if none is registered.
341func Get(name string) interface{} {
342 return DefaultRegistry.Get(name)
343}
344
345// Gets an existing metric or creates and registers a new one. Threadsafe
346// alternative to calling Get and Register on failure.
347func GetOrRegister(name string, i interface{}) interface{} {
348 return DefaultRegistry.GetOrRegister(name, i)
349}
350
351// Register the given metric under the given name. Returns a DuplicateMetric
352// if a metric by the given name is already registered.
353func Register(name string, i interface{}) error {
354 return DefaultRegistry.Register(name, i)
355}
356
357// Register the given metric under the given name. Panics if a metric by the
358// given name is already registered.
359func MustRegister(name string, i interface{}) {
360 if err := Register(name, i); err != nil {
361 panic(err)
362 }
363}
364
365// Run all registered healthchecks.
366func RunHealthchecks() {
367 DefaultRegistry.RunHealthchecks()
368}
369
370// Unregister the metric with the given name.
371func Unregister(name string) {
372 DefaultRegistry.Unregister(name)
373}