mike dupont
init: retro-sync API server + viewer + 71 Bach tiles + catalog
1295969
//! Six Sigma Prometheus CTQ metrics.
use crate::AppState;
use axum::{extract::State, response::IntoResponse};
use std::sync::atomic::{AtomicU64, Ordering};
pub struct CtqMetrics {
pub uploads_total: AtomicU64,
pub defects_total: AtomicU64,
pub band_common: AtomicU64,
pub band_rare: AtomicU64,
pub band_legendary: AtomicU64,
latency_sum_ms: AtomicU64,
latency_count: AtomicU64,
}
impl Default for CtqMetrics {
fn default() -> Self {
Self::new()
}
}
impl CtqMetrics {
pub fn new() -> Self {
Self {
uploads_total: AtomicU64::new(0),
defects_total: AtomicU64::new(0),
band_common: AtomicU64::new(0),
band_rare: AtomicU64::new(0),
band_legendary: AtomicU64::new(0),
latency_sum_ms: AtomicU64::new(0),
latency_count: AtomicU64::new(0),
}
}
pub fn record_defect(&self, _kind: &str) {
self.defects_total.fetch_add(1, Ordering::Relaxed);
}
pub fn record_band(&self, band: u8) {
self.uploads_total.fetch_add(1, Ordering::Relaxed);
match band {
0 => self.band_common.fetch_add(1, Ordering::Relaxed),
1 => self.band_rare.fetch_add(1, Ordering::Relaxed),
_ => self.band_legendary.fetch_add(1, Ordering::Relaxed),
};
}
pub fn record_latency(&self, _name: &str, ms: f64) {
self.latency_sum_ms.fetch_add(ms as u64, Ordering::Relaxed);
self.latency_count.fetch_add(1, Ordering::Relaxed);
}
pub fn band_distribution_in_control(&self) -> bool {
let total = self.uploads_total.load(Ordering::Relaxed);
if total < 30 {
return true;
}
let common = self.band_common.load(Ordering::Relaxed) as f64 / total as f64;
(common - 7.0 / 15.0).abs() <= 0.15
}
pub fn metrics_text(&self) -> String {
let up = self.uploads_total.load(Ordering::Relaxed);
let de = self.defects_total.load(Ordering::Relaxed);
let dpmo = if up > 0 { de * 1_000_000 / up } else { 0 };
format!(
"# HELP retrosync_uploads_total Total uploads\n\
retrosync_uploads_total {up}\n\
retrosync_defects_total {de}\n\
retrosync_dpmo {dpmo}\n\
retrosync_band_common {}\n\
retrosync_band_rare {}\n\
retrosync_band_legendary {}\n\
retrosync_band_in_control {}\n",
self.band_common.load(Ordering::Relaxed),
self.band_rare.load(Ordering::Relaxed),
self.band_legendary.load(Ordering::Relaxed),
self.band_distribution_in_control() as u8,
)
}
}
pub async fn handler(State(state): State<AppState>) -> impl IntoResponse {
state.metrics.metrics_text()
}