github.com/sereiner/library@v0.0.0-20200518095232-1fa3e640cc5f/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 // Gets an existing metric or registers the given one. 33 // The interface can be the metric to register if not found in registry, 34 // or a function returning the metric for lazy instantiation. 35 GetOrRegister(string, interface{}) interface{} 36 37 // Register the given metric under the given name. 38 Register(string, interface{}) error 39 40 // Run all registered healthchecks. 41 RunHealthchecks() 42 43 // Unregister the metric with the given name. 44 Unregister(string) 45 46 // Unregister all metrics. (Mostly for testing.) 47 UnregisterAll() 48 } 49 50 // The standard implementation of a Registry is a mutex-protected map 51 // of names to metrics. 52 type StandardRegistry struct { 53 metrics map[string]interface{} 54 mutex sync.Mutex 55 } 56 57 // Create a new registry. 58 func NewRegistry() Registry { 59 return &StandardRegistry{metrics: make(map[string]interface{})} 60 } 61 62 // Call the given function for each registered metric. 63 func (r *StandardRegistry) Each(f func(string, interface{})) { 64 for name, i := range r.registered() { 65 f(name, i) 66 } 67 } 68 69 // Get the metric by the given name or nil if none is registered. 70 func (r *StandardRegistry) Get(name string) interface{} { 71 r.mutex.Lock() 72 defer r.mutex.Unlock() 73 return r.metrics[name] 74 } 75 76 // Gets an existing metric or creates and registers a new one. Threadsafe 77 // alternative to calling Get and Register on failure. 78 // The interface can be the metric to register if not found in registry, 79 // or a function returning the metric for lazy instantiation. 80 func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} { 81 r.mutex.Lock() 82 defer r.mutex.Unlock() 83 if metric, ok := r.metrics[name]; ok { 84 return metric 85 } 86 if v := reflect.ValueOf(i); v.Kind() == reflect.Func { 87 i = v.Call(nil)[0].Interface() 88 } 89 r.register(name, i) 90 return i 91 } 92 93 // Register the given metric under the given name. Returns a DuplicateMetric 94 // if a metric by the given name is already registered. 95 func (r *StandardRegistry) Register(name string, i interface{}) error { 96 r.mutex.Lock() 97 defer r.mutex.Unlock() 98 return r.register(name, i) 99 } 100 101 // Run all registered healthchecks. 102 func (r *StandardRegistry) RunHealthchecks() { 103 r.mutex.Lock() 104 defer r.mutex.Unlock() 105 for _, i := range r.metrics { 106 if h, ok := i.(Healthcheck); ok { 107 h.Check() 108 } 109 } 110 } 111 112 // Unregister the metric with the given name. 113 func (r *StandardRegistry) Unregister(name string) { 114 r.mutex.Lock() 115 defer r.mutex.Unlock() 116 delete(r.metrics, name) 117 } 118 119 // Unregister all metrics. (Mostly for testing.) 120 func (r *StandardRegistry) UnregisterAll() { 121 r.mutex.Lock() 122 defer r.mutex.Unlock() 123 for name, _ := range r.metrics { 124 delete(r.metrics, name) 125 } 126 } 127 128 func (r *StandardRegistry) register(name string, i interface{}) error { 129 if _, ok := r.metrics[name]; ok { 130 return DuplicateMetric(name) 131 } 132 switch i.(type) { 133 case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, IQPS: 134 r.metrics[name] = i 135 } 136 return nil 137 } 138 139 func (r *StandardRegistry) registered() map[string]interface{} { 140 r.mutex.Lock() 141 defer r.mutex.Unlock() 142 metrics := make(map[string]interface{}, len(r.metrics)) 143 for name, i := range r.metrics { 144 metrics[name] = i 145 } 146 return metrics 147 } 148 149 type PrefixedRegistry struct { 150 underlying Registry 151 prefix string 152 } 153 154 func NewPrefixedRegistry(prefix string) Registry { 155 return &PrefixedRegistry{ 156 underlying: NewRegistry(), 157 prefix: prefix, 158 } 159 } 160 161 func NewPrefixedChildRegistry(parent Registry, prefix string) Registry { 162 return &PrefixedRegistry{ 163 underlying: parent, 164 prefix: prefix, 165 } 166 } 167 168 // Call the given function for each registered metric. 169 func (r *PrefixedRegistry) Each(fn func(string, interface{})) { 170 wrappedFn := func(prefix string) func(string, interface{}) { 171 return func(name string, iface interface{}) { 172 if strings.HasPrefix(name, prefix) { 173 fn(name, iface) 174 } else { 175 return 176 } 177 } 178 } 179 180 baseRegistry, prefix := findPrefix(r, "") 181 baseRegistry.Each(wrappedFn(prefix)) 182 } 183 184 func findPrefix(registry Registry, prefix string) (Registry, string) { 185 switch r := registry.(type) { 186 case *PrefixedRegistry: 187 return findPrefix(r.underlying, r.prefix+prefix) 188 case *StandardRegistry: 189 return r, prefix 190 } 191 return nil, "" 192 } 193 194 // Get the metric by the given name or nil if none is registered. 195 func (r *PrefixedRegistry) Get(name string) interface{} { 196 realName := r.prefix + name 197 return r.underlying.Get(realName) 198 } 199 200 // Gets an existing metric or registers the given one. 201 // The interface can be the metric to register if not found in registry, 202 // or a function returning the metric for lazy instantiation. 203 func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} { 204 realName := r.prefix + name 205 return r.underlying.GetOrRegister(realName, metric) 206 } 207 208 // Register the given metric under the given name. The name will be prefixed. 209 func (r *PrefixedRegistry) Register(name string, metric interface{}) error { 210 realName := r.prefix + name 211 return r.underlying.Register(realName, metric) 212 } 213 214 // Run all registered healthchecks. 215 func (r *PrefixedRegistry) RunHealthchecks() { 216 r.underlying.RunHealthchecks() 217 } 218 219 // Unregister the metric with the given name. The name will be prefixed. 220 func (r *PrefixedRegistry) Unregister(name string) { 221 realName := r.prefix + name 222 r.underlying.Unregister(realName) 223 } 224 225 // Unregister all metrics. (Mostly for testing.) 226 func (r *PrefixedRegistry) UnregisterAll() { 227 r.underlying.UnregisterAll() 228 } 229 230 var DefaultRegistry Registry = NewRegistry() 231 232 // Call the given function for each registered metric. 233 func Each(f func(string, interface{})) { 234 DefaultRegistry.Each(f) 235 } 236 237 // Get the metric by the given name or nil if none is registered. 238 func Get(name string) interface{} { 239 return DefaultRegistry.Get(name) 240 } 241 242 // Gets an existing metric or creates and registers a new one. Threadsafe 243 // alternative to calling Get and Register on failure. 244 func GetOrRegister(name string, i interface{}) interface{} { 245 return DefaultRegistry.GetOrRegister(name, i) 246 } 247 248 // Register the given metric under the given name. Returns a DuplicateMetric 249 // if a metric by the given name is already registered. 250 func Register(name string, i interface{}) error { 251 return DefaultRegistry.Register(name, i) 252 } 253 254 // Register the given metric under the given name. Panics if a metric by the 255 // given name is already registered. 256 func MustRegister(name string, i interface{}) { 257 if err := Register(name, i); err != nil { 258 panic(err) 259 } 260 } 261 262 // Run all registered healthchecks. 263 func RunHealthchecks() { 264 DefaultRegistry.RunHealthchecks() 265 } 266 267 // Unregister the metric with the given name. 268 func Unregister(name string) { 269 DefaultRegistry.Unregister(name) 270 }