rust_serv/metrics/
gauge.rs1use std::sync::atomic::{AtomicI64, Ordering};
4
5#[derive(Debug)]
7pub struct Gauge {
8 value: AtomicI64,
9 name: String,
10 help: String,
11}
12
13impl Gauge {
14 pub fn new(name: impl Into<String>, help: impl Into<String>) -> Self {
16 Self {
17 value: AtomicI64::new(0),
18 name: name.into(),
19 help: help.into(),
20 }
21 }
22
23 pub fn set(&self, value: i64) {
25 self.value.store(value, Ordering::Relaxed);
26 }
27
28 pub fn inc(&self) {
30 self.value.fetch_add(1, Ordering::Relaxed);
31 }
32
33 pub fn dec(&self) {
35 self.value.fetch_sub(1, Ordering::Relaxed);
36 }
37
38 pub fn add(&self, delta: i64) {
40 self.value.fetch_add(delta, Ordering::Relaxed);
41 }
42
43 pub fn sub(&self, delta: i64) {
45 self.value.fetch_sub(delta, Ordering::Relaxed);
46 }
47
48 pub fn get(&self) -> i64 {
50 self.value.load(Ordering::Relaxed)
51 }
52
53 pub fn name(&self) -> &str {
55 &self.name
56 }
57
58 pub fn help(&self) -> &str {
60 &self.help
61 }
62}
63
64impl Clone for Gauge {
65 fn clone(&self) -> Self {
66 Self {
67 value: AtomicI64::new(self.value.load(Ordering::Relaxed)),
68 name: self.name.clone(),
69 help: self.help.clone(),
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_gauge_creation() {
80 let gauge = Gauge::new("active_connections", "Number of active connections");
81 assert_eq!(gauge.get(), 0);
82 assert_eq!(gauge.name(), "active_connections");
83 assert_eq!(gauge.help(), "Number of active connections");
84 }
85
86 #[test]
87 fn test_gauge_set() {
88 let gauge = Gauge::new("test", "test gauge");
89 gauge.set(42);
90 assert_eq!(gauge.get(), 42);
91
92 gauge.set(100);
93 assert_eq!(gauge.get(), 100);
94 }
95
96 #[test]
97 fn test_gauge_inc_dec() {
98 let gauge = Gauge::new("test", "test gauge");
99 gauge.inc();
100 assert_eq!(gauge.get(), 1);
101
102 gauge.inc();
103 assert_eq!(gauge.get(), 2);
104
105 gauge.dec();
106 assert_eq!(gauge.get(), 1);
107 }
108
109 #[test]
110 fn test_gauge_add_sub() {
111 let gauge = Gauge::new("test", "test gauge");
112 gauge.add(10);
113 assert_eq!(gauge.get(), 10);
114
115 gauge.sub(3);
116 assert_eq!(gauge.get(), 7);
117 }
118
119 #[test]
120 fn test_gauge_negative_values() {
121 let gauge = Gauge::new("test", "test gauge");
122 gauge.set(-5);
123 assert_eq!(gauge.get(), -5);
124
125 gauge.add(10);
126 assert_eq!(gauge.get(), 5);
127
128 gauge.sub(20);
129 assert_eq!(gauge.get(), -15);
130 }
131
132 #[test]
133 fn test_gauge_clone() {
134 let gauge = Gauge::new("test", "test gauge");
135 gauge.set(50);
136
137 let cloned = gauge.clone();
138 assert_eq!(cloned.get(), 50);
139 assert_eq!(cloned.name(), "test");
140 }
141
142 #[test]
143 fn test_gauge_concurrent_access() {
144 use std::sync::Arc;
145 use std::thread;
146
147 let gauge = Arc::new(Gauge::new("test", "test gauge"));
148 let mut handles = vec![];
149
150 for _ in 0..5 {
151 let gauge_clone = Arc::clone(&gauge);
152 handles.push(thread::spawn(move || {
153 gauge_clone.inc();
154 }));
155 }
156
157 for _ in 0..3 {
158 let gauge_clone = Arc::clone(&gauge);
159 handles.push(thread::spawn(move || {
160 gauge_clone.dec();
161 }));
162 }
163
164 for handle in handles {
165 handle.join().unwrap();
166 }
167
168 assert_eq!(gauge.get(), 2);
170 }
171}