github.com/amazechain/amc@v0.1.3/internal/metrics/prometheus/registry.go (about) 1 package prometheus 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 8 metrics2 "github.com/VictoriaMetrics/metrics" 9 "github.com/ledgerwatch/log/v3" 10 ) 11 12 // DuplicateMetric is the error returned by Registry.Register when a metric 13 // already exists. If you mean to Register that metric you must first 14 // Unregister the existing metric. 15 type DuplicateMetric string 16 17 func (err DuplicateMetric) Error() string { 18 return fmt.Sprintf("duplicate metric: %s", string(err)) 19 } 20 21 // A Registry holds references to a set of metrics by name and can iterate 22 // over them, calling callback functions provided by the user. 23 // 24 // This is an interface so as to encourage other structs to implement 25 // the Registry API as appropriate. 26 type Registry interface { 27 28 // Call the given function for each registered metric. 29 Each(func(string, interface{})) 30 31 // Get the metric by the given name or nil if none is registered. 32 Get(string) interface{} 33 34 // Gets an existing metric or registers the given one. 35 // The interface can be the metric to register if not found in registry, 36 // or a function returning the metric for lazy instantiation. 37 GetOrRegister(string, interface{}) interface{} 38 39 // Register the given metric under the given name. 40 Register(string, interface{}) error 41 42 // Unregister the metric with the given name. 43 Unregister(string) 44 45 // Unregister all metrics. (Mostly for testing.) 46 UnregisterAll() 47 } 48 49 // The standard implementation of a Registry is a mutex-protected map 50 // of names to metrics. 51 type StandardRegistry struct { 52 metrics map[string]interface{} 53 mutex sync.Mutex 54 } 55 56 // Create a new registry. 57 func NewRegistry() Registry { 58 return &StandardRegistry{metrics: make(map[string]interface{})} 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 r.mutex.Lock() 71 defer r.mutex.Unlock() 72 return r.metrics[name] 73 } 74 75 // Gets an existing metric or creates and registers a new one. Threadsafe 76 // alternative to calling Get and Register on failure. 77 // The interface can be the metric to register if not found in registry, 78 // or a function returning the metric for lazy instantiation. 79 func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} { 80 r.mutex.Lock() 81 defer r.mutex.Unlock() 82 if metric, ok := r.metrics[name]; ok { 83 return metric 84 } 85 if v := reflect.ValueOf(i); v.Kind() == reflect.Func { 86 i = v.Call(nil)[0].Interface() 87 } 88 r.register(name, i) 89 return i 90 } 91 92 // Register the given metric under the given name. Returns a DuplicateMetric 93 // if a metric by the given name is already registered. 94 func (r *StandardRegistry) Register(name string, i interface{}) error { 95 r.mutex.Lock() 96 defer r.mutex.Unlock() 97 return r.register(name, i) 98 } 99 100 // Unregister the metric with the given name. 101 func (r *StandardRegistry) Unregister(name string) { 102 r.mutex.Lock() 103 defer r.mutex.Unlock() 104 r.stop(name) 105 delete(r.metrics, name) 106 } 107 108 // Unregister all metrics. (Mostly for testing.) 109 func (r *StandardRegistry) UnregisterAll() { 110 r.mutex.Lock() 111 defer r.mutex.Unlock() 112 for name := range r.metrics { 113 r.stop(name) 114 delete(r.metrics, name) 115 } 116 } 117 118 func (r *StandardRegistry) register(name string, i interface{}) error { 119 if _, ok := r.metrics[name]; ok { 120 return DuplicateMetric(name) 121 } 122 switch i.(type) { 123 case *metrics2.Counter, *metrics2.Gauge, *metrics2.FloatCounter, *metrics2.Histogram, *metrics2.Summary: 124 r.metrics[name] = i 125 default: 126 log.Info("Type not registered(metrics won't show): ", reflect.TypeOf(i)) 127 } 128 return nil 129 } 130 131 func (r *StandardRegistry) registered() map[string]interface{} { 132 r.mutex.Lock() 133 defer r.mutex.Unlock() 134 metrics := make(map[string]interface{}, len(r.metrics)) 135 for name, i := range r.metrics { 136 metrics[name] = i 137 } 138 return metrics 139 } 140 141 func (r *StandardRegistry) stop(name string) { 142 if i, ok := r.metrics[name]; ok { 143 if s, ok := i.(Stoppable); ok { 144 s.Stop() 145 } 146 } 147 } 148 149 // Stoppable defines the metrics which has to be stopped. 150 type Stoppable interface { 151 Stop() 152 } 153 154 var ( 155 DefaultRegistry = NewRegistry() 156 EphemeralRegistry = NewRegistry() 157 AccountingRegistry = NewRegistry() // registry used in swarm 158 ) 159 160 // Get the metric by the given name or nil if none is registered. 161 func Get(name string) interface{} { 162 return DefaultRegistry.Get(name) 163 }