github.com/theQRL/go-zond@v0.1.1/metrics/registry.go (about) 1 package metrics 2 3 import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "strings" 8 "sync" 9 ) 10 11 // DuplicateMetric is the error returned by Registry.Register when a metric 12 // already exists. If you mean to Register that metric you must first 13 // Unregister the existing metric. 14 type DuplicateMetric string 15 16 func (err DuplicateMetric) Error() string { 17 return fmt.Sprintf("duplicate metric: %s", string(err)) 18 } 19 20 // A Registry holds references to a set of metrics by name and can iterate 21 // over them, calling callback functions provided by the user. 22 // 23 // This is an interface so as to encourage other structs to implement 24 // the Registry API as appropriate. 25 type Registry interface { 26 27 // Call the given function for each registered metric. 28 Each(func(string, interface{})) 29 30 // Get the metric by the given name or nil if none is registered. 31 Get(string) interface{} 32 33 // GetAll metrics in the Registry. 34 GetAll() map[string]map[string]interface{} 35 36 // Gets an existing metric or registers the given one. 37 // The interface can be the metric to register if not found in registry, 38 // or a function returning the metric for lazy instantiation. 39 GetOrRegister(string, interface{}) interface{} 40 41 // Register the given metric under the given name. 42 Register(string, interface{}) error 43 44 // Run all registered healthchecks. 45 RunHealthchecks() 46 47 // Unregister the metric with the given name. 48 Unregister(string) 49 } 50 51 type orderedRegistry struct { 52 StandardRegistry 53 } 54 55 // Call the given function for each registered metric. 56 func (r *orderedRegistry) Each(f func(string, interface{})) { 57 var names []string 58 reg := r.registered() 59 for name := range reg { 60 names = append(names, name) 61 } 62 sort.Strings(names) 63 for _, name := range names { 64 f(name, reg[name]) 65 } 66 } 67 68 // NewRegistry creates a new registry. 69 func NewRegistry() Registry { 70 return new(StandardRegistry) 71 } 72 73 // NewOrderedRegistry creates a new ordered registry (for testing). 74 func NewOrderedRegistry() Registry { 75 return new(orderedRegistry) 76 } 77 78 // The standard implementation of a Registry uses sync.map 79 // of names to metrics. 80 type StandardRegistry struct { 81 metrics sync.Map 82 } 83 84 // Call the given function for each registered metric. 85 func (r *StandardRegistry) Each(f func(string, interface{})) { 86 for name, i := range r.registered() { 87 f(name, i) 88 } 89 } 90 91 // Get the metric by the given name or nil if none is registered. 92 func (r *StandardRegistry) Get(name string) interface{} { 93 item, _ := r.metrics.Load(name) 94 return item 95 } 96 97 // Gets an existing metric or creates and registers a new one. Threadsafe 98 // alternative to calling Get and Register on failure. 99 // The interface can be the metric to register if not found in registry, 100 // or a function returning the metric for lazy instantiation. 101 func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} { 102 // fast path 103 cached, ok := r.metrics.Load(name) 104 if ok { 105 return cached 106 } 107 if v := reflect.ValueOf(i); v.Kind() == reflect.Func { 108 i = v.Call(nil)[0].Interface() 109 } 110 item, _, ok := r.loadOrRegister(name, i) 111 if !ok { 112 return i 113 } 114 return item 115 } 116 117 // Register the given metric under the given name. Returns a DuplicateMetric 118 // if a metric by the given name is already registered. 119 func (r *StandardRegistry) Register(name string, i interface{}) error { 120 // fast path 121 _, ok := r.metrics.Load(name) 122 if ok { 123 return DuplicateMetric(name) 124 } 125 126 if v := reflect.ValueOf(i); v.Kind() == reflect.Func { 127 i = v.Call(nil)[0].Interface() 128 } 129 _, loaded, _ := r.loadOrRegister(name, i) 130 if loaded { 131 return DuplicateMetric(name) 132 } 133 return nil 134 } 135 136 // Run all registered healthchecks. 137 func (r *StandardRegistry) RunHealthchecks() { 138 r.metrics.Range(func(key, value any) bool { 139 if h, ok := value.(Healthcheck); ok { 140 h.Check() 141 } 142 return true 143 }) 144 } 145 146 // GetAll metrics in the Registry 147 func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { 148 data := make(map[string]map[string]interface{}) 149 r.Each(func(name string, i interface{}) { 150 values := make(map[string]interface{}) 151 switch metric := i.(type) { 152 case Counter: 153 values["count"] = metric.Snapshot().Count() 154 case CounterFloat64: 155 values["count"] = metric.Snapshot().Count() 156 case Gauge: 157 values["value"] = metric.Snapshot().Value() 158 case GaugeFloat64: 159 values["value"] = metric.Snapshot().Value() 160 case Healthcheck: 161 values["error"] = nil 162 metric.Check() 163 if err := metric.Error(); nil != err { 164 values["error"] = metric.Error().Error() 165 } 166 case Histogram: 167 h := metric.Snapshot() 168 ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 169 values["count"] = h.Count() 170 values["min"] = h.Min() 171 values["max"] = h.Max() 172 values["mean"] = h.Mean() 173 values["stddev"] = h.StdDev() 174 values["median"] = ps[0] 175 values["75%"] = ps[1] 176 values["95%"] = ps[2] 177 values["99%"] = ps[3] 178 values["99.9%"] = ps[4] 179 case Meter: 180 m := metric.Snapshot() 181 values["count"] = m.Count() 182 values["1m.rate"] = m.Rate1() 183 values["5m.rate"] = m.Rate5() 184 values["15m.rate"] = m.Rate15() 185 values["mean.rate"] = m.RateMean() 186 case Timer: 187 t := metric.Snapshot() 188 ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 189 values["count"] = t.Count() 190 values["min"] = t.Min() 191 values["max"] = t.Max() 192 values["mean"] = t.Mean() 193 values["stddev"] = t.StdDev() 194 values["median"] = ps[0] 195 values["75%"] = ps[1] 196 values["95%"] = ps[2] 197 values["99%"] = ps[3] 198 values["99.9%"] = ps[4] 199 values["1m.rate"] = t.Rate1() 200 values["5m.rate"] = t.Rate5() 201 values["15m.rate"] = t.Rate15() 202 values["mean.rate"] = t.RateMean() 203 } 204 data[name] = values 205 }) 206 return data 207 } 208 209 // Unregister the metric with the given name. 210 func (r *StandardRegistry) Unregister(name string) { 211 r.stop(name) 212 r.metrics.LoadAndDelete(name) 213 } 214 215 func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) { 216 switch i.(type) { 217 case Counter, CounterFloat64, Gauge, GaugeFloat64, GaugeInfo, Healthcheck, Histogram, Meter, Timer, ResettingTimer: 218 default: 219 return nil, false, false 220 } 221 item, loaded := r.metrics.LoadOrStore(name, i) 222 return item, loaded, true 223 } 224 225 func (r *StandardRegistry) registered() map[string]interface{} { 226 metrics := make(map[string]interface{}) 227 r.metrics.Range(func(key, value any) bool { 228 metrics[key.(string)] = value 229 return true 230 }) 231 return metrics 232 } 233 234 func (r *StandardRegistry) stop(name string) { 235 if i, ok := r.metrics.Load(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 var ( 329 DefaultRegistry = NewRegistry() 330 EphemeralRegistry = NewRegistry() 331 AccountingRegistry = NewRegistry() // registry used in swarm 332 ) 333 334 // Call the given function for each registered metric. 335 func Each(f func(string, interface{})) { 336 DefaultRegistry.Each(f) 337 } 338 339 // Get the metric by the given name or nil if none is registered. 340 func Get(name string) interface{} { 341 return DefaultRegistry.Get(name) 342 } 343 344 // Gets an existing metric or creates and registers a new one. Threadsafe 345 // alternative to calling Get and Register on failure. 346 func GetOrRegister(name string, i interface{}) interface{} { 347 return DefaultRegistry.GetOrRegister(name, i) 348 } 349 350 // Register the given metric under the given name. Returns a DuplicateMetric 351 // if a metric by the given name is already registered. 352 func Register(name string, i interface{}) error { 353 return DefaultRegistry.Register(name, i) 354 } 355 356 // Register the given metric under the given name. Panics if a metric by the 357 // given name is already registered. 358 func MustRegister(name string, i interface{}) { 359 if err := Register(name, i); err != nil { 360 panic(err) 361 } 362 } 363 364 // Run all registered healthchecks. 365 func RunHealthchecks() { 366 DefaultRegistry.RunHealthchecks() 367 } 368 369 // Unregister the metric with the given name. 370 func Unregister(name string) { 371 DefaultRegistry.Unregister(name) 372 }