Skip to main content

faucet_cli/sla/
metrics.rs

1//! Prometheus surface for SLA monitoring (#202).
2//!
3//! - `faucet_pipeline_sla_violations_total{pipeline,row,kind}` — counter;
4//!   `kind` ∈ `staleness` | `min_rows` | `volume`.
5//! - `faucet_pipeline_sla_baseline_runs{pipeline,row}` — gauge; successful
6//!   runs currently in the rolling volume baseline (cold-start visibility).
7//!
8//! Emission follows the CLI-side convention (`faucet_schedule_*`,
9//! `faucet_serve_*`): plain `metrics` macros against whatever recorder
10//! `install_observability` installed. Labels stay low-cardinality (`pipeline`
11//! + `row` only, like every pipeline metric — never record keys or run ids).
12
13use metrics::{counter, describe_counter, describe_gauge, gauge};
14use std::sync::Once;
15
16static DESCRIBE: Once = Once::new();
17
18fn describe() {
19    DESCRIBE.call_once(|| {
20        describe_counter!(
21            "faucet_pipeline_sla_violations_total",
22            "SLA violations detected post-run, by kind (staleness | min_rows | volume)"
23        );
24        describe_gauge!(
25            "faucet_pipeline_sla_baseline_runs",
26            "Successful runs currently in the rolling SLA volume baseline"
27        );
28    });
29}
30
31/// Count one detected violation.
32pub fn record_violation(pipeline: &str, row: &str, kind: &'static str) {
33    describe();
34    counter!(
35        "faucet_pipeline_sla_violations_total",
36        "pipeline" => pipeline.to_owned(),
37        "row" => row.to_owned(),
38        "kind" => kind,
39    )
40    .increment(1);
41}
42
43/// Publish the baseline depth after a successful run folds in.
44pub fn set_baseline_runs(pipeline: &str, row: &str, n: usize) {
45    describe();
46    gauge!(
47        "faucet_pipeline_sla_baseline_runs",
48        "pipeline" => pipeline.to_owned(),
49        "row" => row.to_owned(),
50    )
51    .set(n as f64);
52}
53
54#[cfg(test)]
55mod tests {
56    // The emit helpers are exercised end-to-end by the executor integration
57    // tests; here we only pin that they are callable without an installed
58    // recorder (the `metrics` macros no-op) — a panic here would take down
59    // every pipeline run in a build without observability installed.
60    #[test]
61    fn emitting_without_recorder_is_a_noop() {
62        super::record_violation("p", "r", "staleness");
63        super::set_baseline_runs("p", "r", 3);
64    }
65}