github.com/rcrowley/go-metrics@v0.0.0-20201227073835-cf1acfcdf475/registry.go (about) 1 package metrics 2 3 import ( 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. 13 type DuplicateMetric string 14 15 func (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. 24 type 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. 55 type StandardRegistry struct { 56 metrics map[string]interface{} 57 mutex sync.RWMutex 58 } 59 60 // Create a new registry. 61 func NewRegistry() Registry { 62 return &StandardRegistry{metrics: make(map[string]interface{})} 63 } 64 65 // Call the given function for each registered metric. 66 func (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. 75 func (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. 85 func (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. 109 func (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. 116 func (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 127 func (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. 188 func (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.) 196 func (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 205 func (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 216 type metricKV struct { 217 name string 218 value interface{} 219 } 220 221 func (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 234 func (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. 243 type Stoppable interface { 244 Stop() 245 } 246 247 type PrefixedRegistry struct { 248 underlying Registry 249 prefix string 250 } 251 252 func NewPrefixedRegistry(prefix string) Registry { 253 return &PrefixedRegistry{ 254 underlying: NewRegistry(), 255 prefix: prefix, 256 } 257 } 258 259 func 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. 267 func (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 282 func 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. 293 func (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. 301 func (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. 307 func (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. 313 func (r *PrefixedRegistry) RunHealthchecks() { 314 r.underlying.RunHealthchecks() 315 } 316 317 // GetAll metrics in the Registry 318 func (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. 323 func (r *PrefixedRegistry) Unregister(name string) { 324 realName := r.prefix + name 325 r.underlying.Unregister(realName) 326 } 327 328 // Unregister all metrics. (Mostly for testing.) 329 func (r *PrefixedRegistry) UnregisterAll() { 330 r.underlying.UnregisterAll() 331 } 332 333 var DefaultRegistry Registry = NewRegistry() 334 335 // Call the given function for each registered metric. 336 func 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. 341 func 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. 347 func 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. 353 func 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. 359 func MustRegister(name string, i interface{}) { 360 if err := Register(name, i); err != nil { 361 panic(err) 362 } 363 } 364 365 // Run all registered healthchecks. 366 func RunHealthchecks() { 367 DefaultRegistry.RunHealthchecks() 368 } 369 370 // Unregister the metric with the given name. 371 func Unregister(name string) { 372 DefaultRegistry.Unregister(name) 373 }