@@ -45,21 +45,17 @@ type Registry interface {
45
45
46
46
// Unregister the metric with the given name.
47
47
Unregister (string )
48
-
49
- // Unregister all metrics. (Mostly for testing.)
50
- UnregisterAll ()
51
48
}
52
49
53
- // The standard implementation of a Registry is a mutex-protected map
50
+ // The standard implementation of a Registry uses sync. map
54
51
// of names to metrics.
55
52
type StandardRegistry struct {
56
- metrics map [string ]interface {}
57
- mutex sync.Mutex
53
+ metrics sync.Map
58
54
}
59
55
60
56
// Create a new registry.
61
57
func NewRegistry () Registry {
62
- return & StandardRegistry {metrics : make ( map [ string ] interface {}) }
58
+ return & StandardRegistry {}
63
59
}
64
60
65
61
// Call the given function for each registered metric.
@@ -71,45 +67,57 @@ func (r *StandardRegistry) Each(f func(string, interface{})) {
71
67
72
68
// Get the metric by the given name or nil if none is registered.
73
69
func (r * StandardRegistry ) Get (name string ) interface {} {
74
- r .mutex .Lock ()
75
- defer r .mutex .Unlock ()
76
- return r .metrics [name ]
70
+ item , _ := r .metrics .Load (name )
71
+ return item
77
72
}
78
73
79
74
// Gets an existing metric or creates and registers a new one. Threadsafe
80
75
// alternative to calling Get and Register on failure.
81
76
// The interface can be the metric to register if not found in registry,
82
77
// or a function returning the metric for lazy instantiation.
83
78
func (r * StandardRegistry ) GetOrRegister (name string , i interface {}) interface {} {
84
- r . mutex . Lock ()
85
- defer r . mutex . Unlock ( )
86
- if metric , ok := r . metrics [ name ]; ok {
87
- return metric
79
+ // fast path
80
+ cached , ok := r . metrics . Load ( name )
81
+ if ok {
82
+ return cached
88
83
}
89
84
if v := reflect .ValueOf (i ); v .Kind () == reflect .Func {
90
85
i = v .Call (nil )[0 ].Interface ()
91
86
}
92
- r .register (name , i )
93
- return i
87
+ item , _ , ok := r .loadOrRegister (name , i )
88
+ if ! ok {
89
+ return i
90
+ }
91
+ return item
94
92
}
95
93
96
94
// Register the given metric under the given name. Returns a DuplicateMetric
97
95
// if a metric by the given name is already registered.
98
96
func (r * StandardRegistry ) Register (name string , i interface {}) error {
99
- r .mutex .Lock ()
100
- defer r .mutex .Unlock ()
101
- return r .register (name , i )
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
102
111
}
103
112
104
113
// Run all registered healthchecks.
105
114
func (r * StandardRegistry ) RunHealthchecks () {
106
- r .mutex .Lock ()
107
- defer r .mutex .Unlock ()
108
- for _ , i := range r .metrics {
109
- if h , ok := i .(Healthcheck ); ok {
115
+ r .metrics .Range (func (key , value any ) bool {
116
+ if h , ok := value .(Healthcheck ); ok {
110
117
h .Check ()
111
118
}
112
- }
119
+ return true
120
+ })
113
121
}
114
122
115
123
// GetAll metrics in the Registry
@@ -177,45 +185,31 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} {
177
185
178
186
// Unregister the metric with the given name.
179
187
func (r * StandardRegistry ) Unregister (name string ) {
180
- r .mutex .Lock ()
181
- defer r .mutex .Unlock ()
182
188
r .stop (name )
183
- delete (r .metrics , name )
184
- }
185
-
186
- // Unregister all metrics. (Mostly for testing.)
187
- func (r * StandardRegistry ) UnregisterAll () {
188
- r .mutex .Lock ()
189
- defer r .mutex .Unlock ()
190
- for name := range r .metrics {
191
- r .stop (name )
192
- delete (r .metrics , name )
193
- }
189
+ r .metrics .LoadAndDelete (name )
194
190
}
195
191
196
- func (r * StandardRegistry ) register (name string , i interface {}) error {
197
- if _ , ok := r .metrics [name ]; ok {
198
- return DuplicateMetric (name )
199
- }
192
+ func (r * StandardRegistry ) loadOrRegister (name string , i interface {}) (interface {}, bool , bool ) {
200
193
switch i .(type ) {
201
194
case Counter , CounterFloat64 , Gauge , GaugeFloat64 , Healthcheck , Histogram , Meter , Timer , ResettingTimer :
202
- r .metrics [name ] = i
195
+ default :
196
+ return nil , false , false
203
197
}
204
- return nil
198
+ item , loaded := r .metrics .LoadOrStore (name , i )
199
+ return item , loaded , true
205
200
}
206
201
207
202
func (r * StandardRegistry ) registered () map [string ]interface {} {
208
- r .mutex .Lock ()
209
- defer r .mutex .Unlock ()
210
- metrics := make (map [string ]interface {}, len (r .metrics ))
211
- for name , i := range r .metrics {
212
- metrics [name ] = i
213
- }
203
+ metrics := make (map [string ]interface {})
204
+ r .metrics .Range (func (key , value any ) bool {
205
+ metrics [key .(string )] = value
206
+ return true
207
+ })
214
208
return metrics
215
209
}
216
210
217
211
func (r * StandardRegistry ) stop (name string ) {
218
- if i , ok := r .metrics [ name ] ; ok {
212
+ if i , ok := r .metrics . Load ( name ) ; ok {
219
213
if s , ok := i .(Stoppable ); ok {
220
214
s .Stop ()
221
215
}
@@ -308,11 +302,6 @@ func (r *PrefixedRegistry) Unregister(name string) {
308
302
r .underlying .Unregister (realName )
309
303
}
310
304
311
- // Unregister all metrics. (Mostly for testing.)
312
- func (r * PrefixedRegistry ) UnregisterAll () {
313
- r .underlying .UnregisterAll ()
314
- }
315
-
316
305
var (
317
306
DefaultRegistry = NewRegistry ()
318
307
EphemeralRegistry = NewRegistry ()
0 commit comments