rust_serv/metrics/
counter.rs1use std::sync::atomic::{AtomicU64, Ordering};
4
5#[derive(Debug)]
8pub struct Counter {
9 value: AtomicU64,
10 name: String,
11 help: String,
12}
13
14impl Counter {
15 pub fn new(name: impl Into<String>, help: impl Into<String>) -> Self {
17 Self {
18 value: AtomicU64::new(0),
19 name: name.into(),
20 help: help.into(),
21 }
22 }
23
24 pub fn inc(&self) {
26 self.value.fetch_add(1, Ordering::Relaxed);
27 }
28
29 pub fn add(&self, delta: u64) {
31 self.value.fetch_add(delta, Ordering::Relaxed);
32 }
33
34 pub fn get(&self) -> u64 {
36 self.value.load(Ordering::Relaxed)
37 }
38
39 pub fn reset(&self) {
41 self.value.store(0, Ordering::Relaxed);
42 }
43
44 pub fn name(&self) -> &str {
46 &self.name
47 }
48
49 pub fn help(&self) -> &str {
51 &self.help
52 }
53}
54
55impl Clone for Counter {
56 fn clone(&self) -> Self {
57 Self {
58 value: AtomicU64::new(self.value.load(Ordering::Relaxed)),
59 name: self.name.clone(),
60 help: self.help.clone(),
61 }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_counter_creation() {
71 let counter = Counter::new("requests_total", "Total number of requests");
72 assert_eq!(counter.get(), 0);
73 assert_eq!(counter.name(), "requests_total");
74 assert_eq!(counter.help(), "Total number of requests");
75 }
76
77 #[test]
78 fn test_counter_inc() {
79 let counter = Counter::new("test", "test counter");
80 counter.inc();
81 assert_eq!(counter.get(), 1);
82
83 counter.inc();
84 counter.inc();
85 assert_eq!(counter.get(), 3);
86 }
87
88 #[test]
89 fn test_counter_add() {
90 let counter = Counter::new("test", "test counter");
91 counter.add(10);
92 assert_eq!(counter.get(), 10);
93
94 counter.add(5);
95 assert_eq!(counter.get(), 15);
96 }
97
98 #[test]
99 fn test_counter_reset() {
100 let counter = Counter::new("test", "test counter");
101 counter.inc();
102 counter.inc();
103 assert_eq!(counter.get(), 2);
104
105 counter.reset();
106 assert_eq!(counter.get(), 0);
107 }
108
109 #[test]
110 fn test_counter_clone() {
111 let counter = Counter::new("test", "test counter");
112 counter.inc();
113
114 let cloned = counter.clone();
115 assert_eq!(cloned.get(), 1);
116 assert_eq!(cloned.name(), "test");
117 }
118
119 #[test]
120 fn test_counter_concurrent_access() {
121 use std::sync::Arc;
122 use std::thread;
123
124 let counter = Arc::new(Counter::new("test", "test counter"));
125 let mut handles = vec![];
126
127 for _ in 0..10 {
128 let counter_clone = Arc::clone(&counter);
129 handles.push(thread::spawn(move || {
130 counter_clone.inc();
131 }));
132 }
133
134 for handle in handles {
135 handle.join().unwrap();
136 }
137
138 assert_eq!(counter.get(), 10);
139 }
140
141 #[test]
142 fn test_counter_large_values() {
143 let counter = Counter::new("test", "test counter");
144 counter.add(1_000_000);
145 assert_eq!(counter.get(), 1_000_000);
146 }
147}