use std::sync::atomic::{AtomicU64, Ordering};
use serde::{Deserialize, Serialize};
#[allow(clippy::struct_field_names)]
#[derive(Debug, Default)]
pub struct Metrics {
requests_total: AtomicU64,
requests_ok: AtomicU64,
requests_error: AtomicU64,
}
impl Metrics {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn record(&self, ok: bool) {
self.requests_total.fetch_add(1, Ordering::Relaxed);
let bucket = if ok {
&self.requests_ok
} else {
&self.requests_error
};
bucket.fetch_add(1, Ordering::Relaxed);
}
#[must_use]
pub fn snapshot(&self, pools: Vec<PoolSnapshot>) -> StatsSnapshot {
StatsSnapshot {
requests_total: self.requests_total.load(Ordering::Relaxed),
requests_ok: self.requests_ok.load(Ordering::Relaxed),
requests_error: self.requests_error.load(Ordering::Relaxed),
pools,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PoolSnapshot {
pub cluster: String,
pub opened: u64,
pub dispatched: u64,
pub reused: u64,
}
#[allow(clippy::struct_field_names)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StatsSnapshot {
pub requests_total: u64,
pub requests_ok: u64,
pub requests_error: u64,
pub pools: Vec<PoolSnapshot>,
}
impl StatsSnapshot {
#[must_use]
pub fn to_json(&self) -> String {
serde_json::to_string(self)
.unwrap_or_else(|e| format!("{{\"error\":\"stats serialize failed: {e}\"}}"))
}
}
#[cfg(test)]
#[path = "stats_tests.rs"]
mod tests;