github.com/core-coin/go-core/v2@v2.1.9/metrics/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.Mutex 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 for name, i := range r.registered() { 68 f(name, i) 69 } 70 } 71 72 // Get the metric by the given name or nil if none is registered. 73 func (r *StandardRegistry) Get(name string) interface{} { 74 r.mutex.Lock() 75 defer r.mutex.Unlock() 76 return r.metrics[name] 77 } 78 79 // Gets an existing metric or creates and registers a new one. Threadsafe 80 // alternative to calling Get and Register on failure. 81 // The interface can be the metric to register if not found in registry, 82 // or a function returning the metric for lazy instantiation. 83 func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} { 84 r.mutex.Lock() 85 defer r.mutex.Unlock() 86 if metric, ok := r.metrics[name]; ok { 87 return metric 88 } 89 if v := reflect.ValueOf(i); v.Kind() == reflect.Func { 90 i = v.Call(nil)[0].Interface() 91 } 92 r.register(name, i) 93 return i 94 } 95 96 // Register the given metric under the given name. Returns a DuplicateMetric 97 // if a metric by the given name is already registered. 98 func (r *StandardRegistry) Register(name string, i interface{}) error { 99 r.mutex.Lock() 100 defer r.mutex.Unlock() 101 return r.register(name, i) 102 } 103 104 // Run all registered healthchecks. 105 func (r *StandardRegistry) RunHealthchecks() { 106 r.mutex.Lock() 107 defer r.mutex.Unlock() 108 for _, i := range r.metrics { 109 if h, ok := i.(Healthcheck); ok { 110 h.Check() 111 } 112 } 113 } 114 115 // GetAll metrics in the Registry 116 func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { 117 data := make(map[string]map[string]interface{}) 118 r.Each(func(name string, i interface{}) { 119 values := make(map[string]interface{}) 120 switch metric := i.(type) { 121 case Counter: 122 values["count"] = metric.Count() 123 case Gauge: 124 values["value"] = metric.Value() 125 case GaugeFloat64: 126 values["value"] = metric.Value() 127 case Healthcheck: 128 values["error"] = nil 129 metric.Check() 130 if err := metric.Error(); nil != err { 131 values["error"] = metric.Error().Error() 132 } 133 case Histogram: 134 h := metric.Snapshot() 135 ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 136 values["count"] = h.Count() 137 values["min"] = h.Min() 138 values["max"] = h.Max() 139 values["mean"] = h.Mean() 140 values["stddev"] = h.StdDev() 141 values["median"] = ps[0] 142 values["75%"] = ps[1] 143 values["95%"] = ps[2] 144 values["99%"] = ps[3] 145 values["99.9%"] = ps[4] 146 case Meter: 147 m := metric.Snapshot() 148 values["count"] = m.Count() 149 values["1m.rate"] = m.Rate1() 150 values["5m.rate"] = m.Rate5() 151 values["15m.rate"] = m.Rate15() 152 values["mean.rate"] = m.RateMean() 153 case Timer: 154 t := metric.Snapshot() 155 ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 156 values["count"] = t.Count() 157 values["min"] = t.Min() 158 values["max"] = t.Max() 159 values["mean"] = t.Mean() 160 values["stddev"] = t.StdDev() 161 values["median"] = ps[0] 162 values["75%"] = ps[1] 163 values["95%"] = ps[2] 164 values["99%"] = ps[3] 165 values["99.9%"] = ps[4] 166 values["1m.rate"] = t.Rate1() 167 values["5m.rate"] = t.Rate5() 168 values["15m.rate"] = t.Rate15() 169 values["mean.rate"] = t.RateMean() 170 } 171 data[name] = values 172 }) 173 return data 174 } 175 176 // Unregister the metric with the given name. 177 func (r *StandardRegistry) Unregister(name string) { 178 r.mutex.Lock() 179 defer r.mutex.Unlock() 180 r.stop(name) 181 delete(r.metrics, name) 182 } 183 184 // Unregister all metrics. (Mostly for testing.) 185 func (r *StandardRegistry) UnregisterAll() { 186 r.mutex.Lock() 187 defer r.mutex.Unlock() 188 for name := range r.metrics { 189 r.stop(name) 190 delete(r.metrics, name) 191 } 192 } 193 194 func (r *StandardRegistry) register(name string, i interface{}) error { 195 if _, ok := r.metrics[name]; ok { 196 return DuplicateMetric(name) 197 } 198 switch i.(type) { 199 case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: 200 r.metrics[name] = i 201 } 202 return nil 203 } 204 205 func (r *StandardRegistry) registered() map[string]interface{} { 206 r.mutex.Lock() 207 defer r.mutex.Unlock() 208 metrics := make(map[string]interface{}, len(r.metrics)) 209 for name, i := range r.metrics { 210 metrics[name] = i 211 } 212 return metrics 213 } 214 215 func (r *StandardRegistry) stop(name string) { 216 if i, ok := r.metrics[name]; ok { 217 if s, ok := i.(Stoppable); ok { 218 s.Stop() 219 } 220 } 221 } 222 223 // Stoppable defines the metrics which has to be stopped. 224 type Stoppable interface { 225 Stop() 226 } 227 228 type PrefixedRegistry struct { 229 underlying Registry 230 prefix string 231 } 232 233 func NewPrefixedRegistry(prefix string) Registry { 234 return &PrefixedRegistry{ 235 underlying: NewRegistry(), 236 prefix: prefix, 237 } 238 } 239 240 func NewPrefixedChildRegistry(parent Registry, prefix string) Registry { 241 return &PrefixedRegistry{ 242 underlying: parent, 243 prefix: prefix, 244 } 245 } 246 247 // Call the given function for each registered metric. 248 func (r *PrefixedRegistry) Each(fn func(string, interface{})) { 249 wrappedFn := func(prefix string) func(string, interface{}) { 250 return func(name string, iface interface{}) { 251 if strings.HasPrefix(name, prefix) { 252 fn(name, iface) 253 } else { 254 return 255 } 256 } 257 } 258 259 baseRegistry, prefix := findPrefix(r, "") 260 baseRegistry.Each(wrappedFn(prefix)) 261 } 262 263 func findPrefix(registry Registry, prefix string) (Registry, string) { 264 switch r := registry.(type) { 265 case *PrefixedRegistry: 266 return findPrefix(r.underlying, r.prefix+prefix) 267 case *StandardRegistry: 268 return r, prefix 269 } 270 return nil, "" 271 } 272 273 // Get the metric by the given name or nil if none is registered. 274 func (r *PrefixedRegistry) Get(name string) interface{} { 275 realName := r.prefix + name 276 return r.underlying.Get(realName) 277 } 278 279 // Gets an existing metric or registers the given one. 280 // The interface can be the metric to register if not found in registry, 281 // or a function returning the metric for lazy instantiation. 282 func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} { 283 realName := r.prefix + name 284 return r.underlying.GetOrRegister(realName, metric) 285 } 286 287 // Register the given metric under the given name. The name will be prefixed. 288 func (r *PrefixedRegistry) Register(name string, metric interface{}) error { 289 realName := r.prefix + name 290 return r.underlying.Register(realName, metric) 291 } 292 293 // Run all registered healthchecks. 294 func (r *PrefixedRegistry) RunHealthchecks() { 295 r.underlying.RunHealthchecks() 296 } 297 298 // GetAll metrics in the Registry 299 func (r *PrefixedRegistry) GetAll() map[string]map[string]interface{} { 300 return r.underlying.GetAll() 301 } 302 303 // Unregister the metric with the given name. The name will be prefixed. 304 func (r *PrefixedRegistry) Unregister(name string) { 305 realName := r.prefix + name 306 r.underlying.Unregister(realName) 307 } 308 309 // Unregister all metrics. (Mostly for testing.) 310 func (r *PrefixedRegistry) UnregisterAll() { 311 r.underlying.UnregisterAll() 312 } 313 314 var ( 315 DefaultRegistry = NewRegistry() 316 EphemeralRegistry = NewRegistry() 317 AccountingRegistry = NewRegistry() // registry used in swarm 318 ) 319 320 // Call the given function for each registered metric. 321 func Each(f func(string, interface{})) { 322 DefaultRegistry.Each(f) 323 } 324 325 // Get the metric by the given name or nil if none is registered. 326 func Get(name string) interface{} { 327 return DefaultRegistry.Get(name) 328 } 329 330 // Gets an existing metric or creates and registers a new one. Threadsafe 331 // alternative to calling Get and Register on failure. 332 func GetOrRegister(name string, i interface{}) interface{} { 333 return DefaultRegistry.GetOrRegister(name, i) 334 } 335 336 // Register the given metric under the given name. Returns a DuplicateMetric 337 // if a metric by the given name is already registered. 338 func Register(name string, i interface{}) error { 339 return DefaultRegistry.Register(name, i) 340 } 341 342 // Register the given metric under the given name. Panics if a metric by the 343 // given name is already registered. 344 func MustRegister(name string, i interface{}) { 345 if err := Register(name, i); err != nil { 346 panic(err) 347 } 348 } 349 350 // Run all registered healthchecks. 351 func RunHealthchecks() { 352 DefaultRegistry.RunHealthchecks() 353 } 354 355 // Unregister the metric with the given name. 356 func Unregister(name string) { 357 DefaultRegistry.Unregister(name) 358 }