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