Skip to main content

krabka_audit/
stats.rs

1//! Shared, lock-free counters for the audit spool.
2//!
3//! The writer updates these counters. The broker scrapes them into Prometheus.
4
5use {
6    crate::ids::RecordCount,
7    krabka_units::prelude::{ByteSize, ByteSizeExt as _},
8    std::sync::atomic::{AtomicU64, Ordering},
9};
10
11/// Cumulative and current spool statistics.
12///
13/// The counters are `AtomicU64`, which cannot hold a quantity. The byte gauge
14/// converts to and from [`ByteSize`] in its accessors.
15#[derive(Debug, Default)]
16pub struct AuditStats {
17    spooled: AtomicU64,
18    replayed: AtomicU64,
19    dropped: AtomicU64,
20    depth: AtomicU64,
21    spool_bytes: AtomicU64,
22}
23
24impl AuditStats {
25    #[must_use]
26    pub fn new() -> Self { Self::default() }
27
28    pub(crate) fn inc_spooled(&self) { self.spooled.fetch_add(1, Ordering::Relaxed); }
29
30    pub(crate) fn inc_replayed_by(&self, n: u64) { self.replayed.fetch_add(n, Ordering::Relaxed); }
31
32    pub(crate) fn inc_dropped(&self) { self.dropped.fetch_add(1, Ordering::Relaxed); }
33
34    pub(crate) fn set_depth(&self, count: RecordCount, size: ByteSize) {
35        self.depth.store(count.0, Ordering::Relaxed);
36        self.spool_bytes.store(size.bytes_u64(), Ordering::Relaxed);
37    }
38
39    #[must_use]
40    pub fn spooled(&self) -> u64 { self.spooled.load(Ordering::Relaxed) }
41
42    #[must_use]
43    pub fn replayed(&self) -> u64 { self.replayed.load(Ordering::Relaxed) }
44
45    #[must_use]
46    pub fn dropped(&self) -> u64 { self.dropped.load(Ordering::Relaxed) }
47
48    #[must_use]
49    pub fn depth(&self) -> u64 { self.depth.load(Ordering::Relaxed) }
50
51    /// Bytes currently held in the spool.
52    ///
53    /// The broker exports this value as the `audit_spool_bytes` gauge, and the
54    /// method takes its name from that gauge.
55    #[must_use]
56    pub fn spool_bytes(&self) -> ByteSize {
57        ByteSize::from_bytes(self.spool_bytes.load(Ordering::Relaxed))
58    }
59}