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