mumble_server_runtime_gateway/
metrics.rs1use std::sync::atomic::{AtomicU64, Ordering};
2
3#[derive(Debug, Default)]
5pub struct VoiceMetrics {
6 ingress_packets: AtomicU64,
7 ingress_bytes: AtomicU64,
8 egress_packets: AtomicU64,
9 egress_bytes: AtomicU64,
10 dropped_packets: AtomicU64,
11}
12
13impl VoiceMetrics {
14 pub(crate) fn ingress(&self, bytes: usize) {
15 self.ingress_packets.fetch_add(1, Ordering::Relaxed);
16 self.ingress_bytes
17 .fetch_add(u64::try_from(bytes).unwrap_or(u64::MAX), Ordering::Relaxed);
18 }
19
20 pub(crate) fn egress(&self, bytes: usize) {
21 self.egress_packets.fetch_add(1, Ordering::Relaxed);
22 self.egress_bytes
23 .fetch_add(u64::try_from(bytes).unwrap_or(u64::MAX), Ordering::Relaxed);
24 }
25
26 pub(crate) fn dropped(&self) {
27 self.dropped_packets.fetch_add(1, Ordering::Relaxed);
28 }
29
30 #[must_use]
31 pub fn snapshot(&self) -> VoiceMetricsSnapshot {
32 VoiceMetricsSnapshot {
33 ingress_packets: self.ingress_packets.load(Ordering::Relaxed),
34 ingress_bytes: self.ingress_bytes.load(Ordering::Relaxed),
35 egress_packets: self.egress_packets.load(Ordering::Relaxed),
36 egress_bytes: self.egress_bytes.load(Ordering::Relaxed),
37 dropped_packets: self.dropped_packets.load(Ordering::Relaxed),
38 }
39 }
40}
41
42#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
43pub struct VoiceMetricsSnapshot {
44 pub ingress_packets: u64,
45 pub ingress_bytes: u64,
46 pub egress_packets: u64,
47 pub egress_bytes: u64,
48 pub dropped_packets: u64,
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn counters_are_monotonic_and_saturating_at_conversion_boundaries() {
57 let metrics = VoiceMetrics::default();
58 metrics.ingress(30);
59 metrics.egress(42);
60 metrics.dropped();
61
62 assert_eq!(
63 metrics.snapshot(),
64 VoiceMetricsSnapshot {
65 ingress_packets: 1,
66 ingress_bytes: 30,
67 egress_packets: 1,
68 egress_bytes: 42,
69 dropped_packets: 1,
70 }
71 );
72 }
73}