oxur_repl/metrics/
server.rs1use metrics::{counter, gauge};
8use std::sync::atomic::{AtomicU64, Ordering};
9
10#[derive(Debug, Default)]
44pub struct ServerMetrics {
45 connections_total: AtomicU64,
47 connections_active: AtomicU64,
48
49 sessions_total: AtomicU64,
51 sessions_active: AtomicU64,
52
53 requests_total: AtomicU64,
55 responses_total: AtomicU64,
56 responses_success: AtomicU64,
57 responses_error: AtomicU64,
58}
59
60#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
62pub struct ServerMetricsSnapshot {
63 pub connections_total: u64,
64 pub connections_active: u64,
65 pub sessions_total: u64,
66 pub sessions_active: u64,
67 pub requests_total: u64,
68 pub responses_total: u64,
69 pub responses_success: u64,
70 pub responses_error: u64,
71}
72
73impl ServerMetrics {
74 pub fn new() -> Self {
76 Self::default()
77 }
78
79 pub fn connection_accepted(&self) {
84 self.connections_total.fetch_add(1, Ordering::Relaxed);
85 self.connections_active.fetch_add(1, Ordering::Relaxed);
86
87 counter!("repl.server.connections_total").increment(1);
88 gauge!("repl.server.connections_active")
89 .set(self.connections_active.load(Ordering::Relaxed) as f64);
90 }
91
92 pub fn connection_closed(&self) {
96 self.connections_active.fetch_sub(1, Ordering::Relaxed);
97
98 gauge!("repl.server.connections_active")
99 .set(self.connections_active.load(Ordering::Relaxed) as f64);
100 }
101
102 pub fn session_created(&self) {
107 self.sessions_total.fetch_add(1, Ordering::Relaxed);
108 self.sessions_active.fetch_add(1, Ordering::Relaxed);
109
110 counter!("repl.server.sessions_total").increment(1);
111 gauge!("repl.server.sessions_active")
112 .set(self.sessions_active.load(Ordering::Relaxed) as f64);
113 }
114
115 pub fn session_closed(&self) {
119 self.sessions_active.fetch_sub(1, Ordering::Relaxed);
120
121 gauge!("repl.server.sessions_active")
122 .set(self.sessions_active.load(Ordering::Relaxed) as f64);
123 }
124
125 pub fn request_received(&self, operation: &'static str) {
133 self.requests_total.fetch_add(1, Ordering::Relaxed);
134
135 counter!("repl.server.requests_total", "operation" => operation).increment(1);
136 }
137
138 pub fn response_sent(&self, status: &'static str) {
146 self.responses_total.fetch_add(1, Ordering::Relaxed);
147
148 match status {
149 "success" => {
150 self.responses_success.fetch_add(1, Ordering::Relaxed);
151 }
152 "error" => {
153 self.responses_error.fetch_add(1, Ordering::Relaxed);
154 }
155 _ => {}
156 }
157
158 counter!("repl.server.responses_total", "status" => status).increment(1);
159 }
160
161 pub fn snapshot(&self) -> ServerMetricsSnapshot {
165 ServerMetricsSnapshot {
166 connections_total: self.connections_total.load(Ordering::Relaxed),
167 connections_active: self.connections_active.load(Ordering::Relaxed),
168 sessions_total: self.sessions_total.load(Ordering::Relaxed),
169 sessions_active: self.sessions_active.load(Ordering::Relaxed),
170 requests_total: self.requests_total.load(Ordering::Relaxed),
171 responses_total: self.responses_total.load(Ordering::Relaxed),
172 responses_success: self.responses_success.load(Ordering::Relaxed),
173 responses_error: self.responses_error.load(Ordering::Relaxed),
174 }
175 }
176
177 pub fn connections_total(&self) -> u64 {
179 self.connections_total.load(Ordering::Relaxed)
180 }
181
182 pub fn connections_active(&self) -> u64 {
184 self.connections_active.load(Ordering::Relaxed)
185 }
186
187 pub fn sessions_total(&self) -> u64 {
189 self.sessions_total.load(Ordering::Relaxed)
190 }
191
192 pub fn sessions_active(&self) -> u64 {
194 self.sessions_active.load(Ordering::Relaxed)
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn test_server_metrics_creation() {
204 let metrics = ServerMetrics::new();
205
206 assert_eq!(metrics.connections_total(), 0);
208 assert_eq!(metrics.connections_active(), 0);
209 assert_eq!(metrics.sessions_total(), 0);
210 assert_eq!(metrics.sessions_active(), 0);
211 }
212
213 #[test]
214 fn test_connection_tracking() {
215 let metrics = ServerMetrics::new();
216
217 metrics.connection_accepted();
218 assert_eq!(metrics.connections_total(), 1);
219 assert_eq!(metrics.connections_active(), 1);
220
221 metrics.connection_accepted();
222 assert_eq!(metrics.connections_total(), 2);
223 assert_eq!(metrics.connections_active(), 2);
224
225 metrics.connection_closed();
226 assert_eq!(metrics.connections_total(), 2);
227 assert_eq!(metrics.connections_active(), 1);
228 }
229
230 #[test]
231 fn test_session_tracking() {
232 let metrics = ServerMetrics::new();
233
234 metrics.session_created();
235 assert_eq!(metrics.sessions_total(), 1);
236 assert_eq!(metrics.sessions_active(), 1);
237
238 metrics.session_closed();
239 assert_eq!(metrics.sessions_total(), 1);
240 assert_eq!(metrics.sessions_active(), 0);
241 }
242
243 #[test]
244 fn test_request_response_tracking() {
245 let metrics = ServerMetrics::new();
246
247 metrics.request_received("eval");
248 metrics.request_received("eval");
249 metrics.request_received("close");
250
251 let snapshot = metrics.snapshot();
252 assert_eq!(snapshot.requests_total, 3);
253
254 metrics.response_sent("success");
255 metrics.response_sent("success");
256 metrics.response_sent("error");
257
258 let snapshot = metrics.snapshot();
259 assert_eq!(snapshot.responses_total, 3);
260 assert_eq!(snapshot.responses_success, 2);
261 assert_eq!(snapshot.responses_error, 1);
262 }
263
264 #[test]
265 fn test_snapshot() {
266 let metrics = ServerMetrics::new();
267
268 metrics.connection_accepted();
269 metrics.session_created();
270 metrics.request_received("eval");
271 metrics.response_sent("success");
272
273 let snapshot = metrics.snapshot();
274
275 assert_eq!(snapshot.connections_total, 1);
276 assert_eq!(snapshot.connections_active, 1);
277 assert_eq!(snapshot.sessions_total, 1);
278 assert_eq!(snapshot.sessions_active, 1);
279 assert_eq!(snapshot.requests_total, 1);
280 assert_eq!(snapshot.responses_total, 1);
281 assert_eq!(snapshot.responses_success, 1);
282 assert_eq!(snapshot.responses_error, 0);
283 }
284}