github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/utilities/metrics/registry.go (about) 1 package metrics 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "sync" 8 ) 9 10 type DuplicateMetric string 11 12 func (err DuplicateMetric) Error() string { 13 return fmt.Sprintf("duplicate metric: %s", string(err)) 14 } 15 16 type Registry interface { 17 Each(func(string, interface{})) 18 19 Get(string) interface{} 20 21 GetAll() map[string]map[string]interface{} 22 23 GetOrRegister(string, interface{}) interface{} 24 25 Register(string, interface{}) error 26 27 RunHealthchecks() 28 29 Unregister(string) 30 31 UnregisterAll() 32 } 33 34 type StandardRegistry struct { 35 metrics map[string]interface{} 36 mutex sync.Mutex 37 } 38 39 func NewRegistry() Registry { 40 return &StandardRegistry{metrics: make(map[string]interface{})} 41 } 42 43 func (r *StandardRegistry) Each(f func(string, interface{})) { 44 for name, i := range r.registered() { 45 f(name, i) 46 } 47 } 48 49 func (r *StandardRegistry) Get(name string) interface{} { 50 r.mutex.Lock() 51 defer r.mutex.Unlock() 52 return r.metrics[name] 53 } 54 55 func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} { 56 r.mutex.Lock() 57 defer r.mutex.Unlock() 58 if metric, ok := r.metrics[name]; ok { 59 return metric 60 } 61 if v := reflect.ValueOf(i); v.Kind() == reflect.Func { 62 i = v.Call(nil)[0].Interface() 63 } 64 r.register(name, i) 65 return i 66 } 67 68 func (r *StandardRegistry) Register(name string, i interface{}) error { 69 r.mutex.Lock() 70 defer r.mutex.Unlock() 71 return r.register(name, i) 72 } 73 74 func (r *StandardRegistry) RunHealthchecks() { 75 r.mutex.Lock() 76 defer r.mutex.Unlock() 77 for _, i := range r.metrics { 78 if h, ok := i.(Healthcheck); ok { 79 h.Check() 80 } 81 } 82 } 83 84 func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { 85 data := make(map[string]map[string]interface{}) 86 r.Each(func(name string, i interface{}) { 87 values := make(map[string]interface{}) 88 switch metric := i.(type) { 89 case Counter: 90 values["count"] = metric.Count() 91 case Gauge: 92 values["value"] = metric.Value() 93 case GaugeFloat64: 94 values["value"] = metric.Value() 95 case Healthcheck: 96 values["error"] = nil 97 metric.Check() 98 if err := metric.Error(); nil != err { 99 values["error"] = metric.Error().Error() 100 } 101 case Histogram: 102 h := metric.Snapshot() 103 ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 104 values["count"] = h.Count() 105 values["min"] = h.Min() 106 values["max"] = h.Max() 107 values["mean"] = h.Mean() 108 values["stddev"] = h.StdDev() 109 values["median"] = ps[0] 110 values["75%"] = ps[1] 111 values["95%"] = ps[2] 112 values["99%"] = ps[3] 113 values["99.9%"] = ps[4] 114 case Meter: 115 m := metric.Snapshot() 116 values["count"] = m.Count() 117 values["1m.rate"] = m.Rate1() 118 values["5m.rate"] = m.Rate5() 119 values["15m.rate"] = m.Rate15() 120 values["mean.rate"] = m.RateMean() 121 case Timer: 122 t := metric.Snapshot() 123 ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) 124 values["count"] = t.Count() 125 values["min"] = t.Min() 126 values["max"] = t.Max() 127 values["mean"] = t.Mean() 128 values["stddev"] = t.StdDev() 129 values["median"] = ps[0] 130 values["75%"] = ps[1] 131 values["95%"] = ps[2] 132 values["99%"] = ps[3] 133 values["99.9%"] = ps[4] 134 values["1m.rate"] = t.Rate1() 135 values["5m.rate"] = t.Rate5() 136 values["15m.rate"] = t.Rate15() 137 values["mean.rate"] = t.RateMean() 138 } 139 data[name] = values 140 }) 141 return data 142 } 143 144 func (r *StandardRegistry) Unregister(name string) { 145 r.mutex.Lock() 146 defer r.mutex.Unlock() 147 r.stop(name) 148 delete(r.metrics, name) 149 } 150 151 func (r *StandardRegistry) UnregisterAll() { 152 r.mutex.Lock() 153 defer r.mutex.Unlock() 154 for name := range r.metrics { 155 r.stop(name) 156 delete(r.metrics, name) 157 } 158 } 159 160 func (r *StandardRegistry) register(name string, i interface{}) error { 161 if _, ok := r.metrics[name]; ok { 162 return DuplicateMetric(name) 163 } 164 switch i.(type) { 165 case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: 166 r.metrics[name] = i 167 } 168 return nil 169 } 170 171 func (r *StandardRegistry) registered() map[string]interface{} { 172 r.mutex.Lock() 173 defer r.mutex.Unlock() 174 metrics := make(map[string]interface{}, len(r.metrics)) 175 for name, i := range r.metrics { 176 metrics[name] = i 177 } 178 return metrics 179 } 180 181 func (r *StandardRegistry) stop(name string) { 182 if i, ok := r.metrics[name]; ok { 183 if s, ok := i.(Stoppable); ok { 184 s.Stop() 185 } 186 } 187 } 188 189 type Stoppable interface { 190 Stop() 191 } 192 193 type PrefixedRegistry struct { 194 underlying Registry 195 prefix string 196 } 197 198 func NewPrefixedRegistry(prefix string) Registry { 199 return &PrefixedRegistry{ 200 underlying: NewRegistry(), 201 prefix: prefix, 202 } 203 } 204 205 func NewPrefixedChildRegistry(parent Registry, prefix string) Registry { 206 return &PrefixedRegistry{ 207 underlying: parent, 208 prefix: prefix, 209 } 210 } 211 212 func (r *PrefixedRegistry) Each(fn func(string, interface{})) { 213 wrappedFn := func(prefix string) func(string, interface{}) { 214 return func(name string, iface interface{}) { 215 if strings.HasPrefix(name, prefix) { 216 fn(name, iface) 217 } else { 218 return 219 } 220 } 221 } 222 223 baseRegistry, prefix := findPrefix(r, "") 224 baseRegistry.Each(wrappedFn(prefix)) 225 } 226 227 func findPrefix(registry Registry, prefix string) (Registry, string) { 228 switch r := registry.(type) { 229 case *PrefixedRegistry: 230 return findPrefix(r.underlying, r.prefix+prefix) 231 case *StandardRegistry: 232 return r, prefix 233 } 234 return nil, "" 235 } 236 237 func (r *PrefixedRegistry) Get(name string) interface{} { 238 realName := r.prefix + name 239 return r.underlying.Get(realName) 240 } 241 242 func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} { 243 realName := r.prefix + name 244 return r.underlying.GetOrRegister(realName, metric) 245 } 246 247 func (r *PrefixedRegistry) Register(name string, metric interface{}) error { 248 realName := r.prefix + name 249 return r.underlying.Register(realName, metric) 250 } 251 252 func (r *PrefixedRegistry) RunHealthchecks() { 253 r.underlying.RunHealthchecks() 254 } 255 256 func (r *PrefixedRegistry) GetAll() map[string]map[string]interface{} { 257 return r.underlying.GetAll() 258 } 259 260 func (r *PrefixedRegistry) Unregister(name string) { 261 realName := r.prefix + name 262 r.underlying.Unregister(realName) 263 } 264 265 func (r *PrefixedRegistry) UnregisterAll() { 266 r.underlying.UnregisterAll() 267 } 268 269 var DefaultRegistry Registry = NewRegistry() 270 271 func Each(f func(string, interface{})) { 272 DefaultRegistry.Each(f) 273 } 274 275 func Get(name string) interface{} { 276 return DefaultRegistry.Get(name) 277 } 278 279 func GetOrRegister(name string, i interface{}) interface{} { 280 return DefaultRegistry.GetOrRegister(name, i) 281 } 282 283 func Register(name string, i interface{}) error { 284 return DefaultRegistry.Register(name, i) 285 } 286 287 func MustRegister(name string, i interface{}) { 288 if err := Register(name, i); err != nil { 289 panic(err) 290 } 291 } 292 293 func RunHealthchecks() { 294 DefaultRegistry.RunHealthchecks() 295 } 296 297 func Unregister(name string) { 298 DefaultRegistry.Unregister(name) 299 }