1use crate::{Counter, Gauge, RateMeter, Timer};
7use std::collections::HashMap;
8use std::sync::{Arc, RwLock};
9
10#[repr(align(64))]
15pub struct Registry {
16 counters: RwLock<HashMap<String, Arc<Counter>>>,
17 gauges: RwLock<HashMap<String, Arc<Gauge>>>,
18 timers: RwLock<HashMap<String, Arc<Timer>>>,
19 rate_meters: RwLock<HashMap<String, Arc<RateMeter>>>,
20}
21
22impl Registry {
23 pub fn new() -> Self {
25 Self {
26 counters: RwLock::new(HashMap::new()),
27 gauges: RwLock::new(HashMap::new()),
28 timers: RwLock::new(HashMap::new()),
29 rate_meters: RwLock::new(HashMap::new()),
30 }
31 }
32
33 pub fn get_or_create_counter(&self, name: &str) -> Arc<Counter> {
35 if let Ok(counters) = self.counters.read() {
37 if let Some(counter) = counters.get(name) {
38 return counter.clone();
39 }
40 }
41
42 let mut counters = self.counters.write().unwrap_or_else(|e| e.into_inner());
44 counters
45 .entry(name.to_string())
46 .or_insert_with(|| Arc::new(Counter::new()))
47 .clone()
48 }
49
50 pub fn get_or_create_gauge(&self, name: &str) -> Arc<Gauge> {
52 if let Ok(gauges) = self.gauges.read() {
54 if let Some(gauge) = gauges.get(name) {
55 return gauge.clone();
56 }
57 }
58
59 let mut gauges = self.gauges.write().unwrap_or_else(|e| e.into_inner());
61 gauges
62 .entry(name.to_string())
63 .or_insert_with(|| Arc::new(Gauge::new()))
64 .clone()
65 }
66
67 pub fn get_or_create_timer(&self, name: &str) -> Arc<Timer> {
69 if let Ok(timers) = self.timers.read() {
71 if let Some(timer) = timers.get(name) {
72 return timer.clone();
73 }
74 }
75
76 let mut timers = self.timers.write().unwrap_or_else(|e| e.into_inner());
78 timers
79 .entry(name.to_string())
80 .or_insert_with(|| Arc::new(Timer::new()))
81 .clone()
82 }
83
84 pub fn get_or_create_rate_meter(&self, name: &str) -> Arc<RateMeter> {
86 if let Ok(rate_meters) = self.rate_meters.read() {
88 if let Some(rate_meter) = rate_meters.get(name) {
89 return rate_meter.clone();
90 }
91 }
92
93 let mut rate_meters = self.rate_meters.write().unwrap_or_else(|e| e.into_inner());
95 rate_meters
96 .entry(name.to_string())
97 .or_insert_with(|| Arc::new(RateMeter::new()))
98 .clone()
99 }
100
101 pub fn counter_names(&self) -> Vec<String> {
103 self.counters
104 .read()
105 .unwrap_or_else(|e| e.into_inner())
106 .keys()
107 .cloned()
108 .collect()
109 }
110
111 pub fn gauge_names(&self) -> Vec<String> {
113 self.gauges
114 .read()
115 .unwrap_or_else(|e| e.into_inner())
116 .keys()
117 .cloned()
118 .collect()
119 }
120
121 pub fn timer_names(&self) -> Vec<String> {
123 self.timers
124 .read()
125 .unwrap_or_else(|e| e.into_inner())
126 .keys()
127 .cloned()
128 .collect()
129 }
130
131 pub fn rate_meter_names(&self) -> Vec<String> {
133 self.rate_meters
134 .read()
135 .unwrap_or_else(|e| e.into_inner())
136 .keys()
137 .cloned()
138 .collect()
139 }
140
141 pub fn metric_count(&self) -> usize {
143 self.counters
144 .read()
145 .unwrap_or_else(|e| e.into_inner())
146 .len()
147 + self.gauges.read().unwrap_or_else(|e| e.into_inner()).len()
148 + self.timers.read().unwrap_or_else(|e| e.into_inner()).len()
149 + self
150 .rate_meters
151 .read()
152 .unwrap_or_else(|e| e.into_inner())
153 .len()
154 }
155
156 pub fn clear(&self) {
158 self.counters
159 .write()
160 .unwrap_or_else(|e| e.into_inner())
161 .clear();
162 self.gauges
163 .write()
164 .unwrap_or_else(|e| e.into_inner())
165 .clear();
166 self.timers
167 .write()
168 .unwrap_or_else(|e| e.into_inner())
169 .clear();
170 self.rate_meters
171 .write()
172 .unwrap_or_else(|e| e.into_inner())
173 .clear();
174 }
175}
176
177impl Default for Registry {
178 fn default() -> Self {
179 Self::new()
180 }
181}
182
183#[cfg(test)]
187mod tests {
188 use super::*;
189 use std::sync::Arc;
190 use std::thread;
191
192 #[test]
193 fn test_counter_registration() {
194 let registry = Registry::new();
195
196 let counter1 = registry.get_or_create_counter("requests");
197 let counter2 = registry.get_or_create_counter("requests");
198
199 assert!(Arc::ptr_eq(&counter1, &counter2));
201 assert_eq!(registry.metric_count(), 1);
202 }
203
204 #[test]
205 fn test_gauge_registration() {
206 let registry = Registry::new();
207
208 let gauge1 = registry.get_or_create_gauge("cpu_usage");
209 let gauge2 = registry.get_or_create_gauge("cpu_usage");
210
211 assert!(Arc::ptr_eq(&gauge1, &gauge2));
213 assert_eq!(registry.metric_count(), 1);
214 }
215
216 #[test]
217 fn test_timer_registration() {
218 let registry = Registry::new();
219
220 let timer1 = registry.get_or_create_timer("db_query");
221 let timer2 = registry.get_or_create_timer("db_query");
222
223 assert!(Arc::ptr_eq(&timer1, &timer2));
225 assert_eq!(registry.metric_count(), 1);
226 }
227
228 #[test]
229 fn test_rate_meter_registration() {
230 let registry = Registry::new();
231
232 let meter1 = registry.get_or_create_rate_meter("api_calls");
233 let meter2 = registry.get_or_create_rate_meter("api_calls");
234
235 assert!(Arc::ptr_eq(&meter1, &meter2));
237 assert_eq!(registry.metric_count(), 1);
238 }
239
240 #[test]
241 fn test_mixed_metrics() {
242 let registry = Registry::new();
243
244 let _counter = registry.get_or_create_counter("requests");
245 let _gauge = registry.get_or_create_gauge("cpu_usage");
246 let _timer = registry.get_or_create_timer("db_query");
247 let _meter = registry.get_or_create_rate_meter("api_calls");
248
249 assert_eq!(registry.metric_count(), 4);
250 assert_eq!(registry.counter_names().len(), 1);
251 assert_eq!(registry.gauge_names().len(), 1);
252 assert_eq!(registry.timer_names().len(), 1);
253 assert_eq!(registry.rate_meter_names().len(), 1);
254 }
255
256 #[test]
257 fn test_concurrent_access() {
258 let registry = Arc::new(Registry::new());
259 let mut handles = vec![];
260
261 for _i in 0..10 {
263 let registry = registry.clone();
264 let handle = thread::spawn(move || {
265 let counter = registry.get_or_create_counter("concurrent_test");
266 counter.inc();
267 counter.get()
268 });
269 handles.push(handle);
270 }
271
272 for handle in handles {
274 handle.join().unwrap();
275 }
276
277 assert_eq!(registry.metric_count(), 1);
279 let counter = registry.get_or_create_counter("concurrent_test");
280 assert_eq!(counter.get(), 10);
281 }
282
283 #[test]
284 fn test_clear() {
285 let registry = Registry::new();
286
287 let _counter = registry.get_or_create_counter("requests");
288 let _gauge = registry.get_or_create_gauge("cpu_usage");
289
290 assert_eq!(registry.metric_count(), 2);
291
292 registry.clear();
293 assert_eq!(registry.metric_count(), 0);
294 }
295
296 #[test]
297 fn test_metric_names() {
298 let registry = Registry::new();
299
300 let _counter1 = registry.get_or_create_counter("requests");
301 let _counter2 = registry.get_or_create_counter("errors");
302 let _gauge1 = registry.get_or_create_gauge("cpu_usage");
303
304 let counter_names = registry.counter_names();
305 let gauge_names = registry.gauge_names();
306
307 assert_eq!(counter_names.len(), 2);
308 assert_eq!(gauge_names.len(), 1);
309 assert!(counter_names.contains(&"requests".to_string()));
310 assert!(counter_names.contains(&"errors".to_string()));
311 assert!(gauge_names.contains(&"cpu_usage".to_string()));
312 }
313
314 #[test]
315 fn test_duplicate_names_across_types_are_independent() {
316 let registry = Registry::new();
317
318 let c = registry.get_or_create_counter("same_name");
319 let g = registry.get_or_create_gauge("same_name");
320 let t = registry.get_or_create_timer("same_name");
321 let r = registry.get_or_create_rate_meter("same_name");
322
323 assert_eq!(registry.metric_count(), 4);
325
326 let c_addr = Arc::as_ptr(&c) as usize;
328 let g_addr = Arc::as_ptr(&g) as usize;
329 let t_addr = Arc::as_ptr(&t) as usize;
330 let r_addr = Arc::as_ptr(&r) as usize;
331
332 assert_ne!(c_addr, g_addr);
333 assert_ne!(c_addr, t_addr);
334 assert_ne!(c_addr, r_addr);
335 assert_ne!(g_addr, t_addr);
336 assert_ne!(g_addr, r_addr);
337 assert_ne!(t_addr, r_addr);
338 }
339
340 #[test]
341 fn test_clear_then_recreate_returns_new_instances() {
342 let registry = Registry::new();
343
344 let counter_before = registry.get_or_create_counter("requests");
345 let gauge_before = registry.get_or_create_gauge("cpu");
346 assert_eq!(registry.metric_count(), 2);
347
348 registry.clear();
350 assert_eq!(registry.metric_count(), 0);
351
352 let counter_after = registry.get_or_create_counter("requests");
353 let gauge_after = registry.get_or_create_gauge("cpu");
354
355 assert!(!Arc::ptr_eq(&counter_before, &counter_after));
357 assert!(!Arc::ptr_eq(&gauge_before, &gauge_after));
358 }
359
360 #[test]
361 fn test_concurrent_duplicate_registration_singleton_per_name() {
362 let registry = Arc::new(Registry::new());
363 let mut handles = vec![];
364
365 for _ in 0..16 {
366 let r = registry.clone();
367 handles.push(thread::spawn(move || r.get_or_create_timer("dup")));
368 }
369
370 let first = registry.get_or_create_timer("dup");
371 for h in handles {
372 let timer = h.join().unwrap();
373 assert!(Arc::ptr_eq(&first, &timer));
374 }
375 assert_eq!(registry.metric_count(), 1);
376 }
377}