Skip to main content

max / makenotwork

1.8 KB · 46 lines History Blame Raw
1 use axum::{extract::State, response::IntoResponse};
2 use metrics::{counter, gauge, histogram};
3 use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusHandle};
4
5 pub fn init() -> PrometheusHandle {
6 PrometheusBuilder::new()
7 .install_recorder()
8 .expect("install prometheus recorder")
9 }
10
11 // --- Emission ---------------------------------------------------------------
12 // The recorder was installed and `/metrics` served, but nothing was ever
13 // measured. These are the emit sites the runner calls so an operator scraping
14 // `/metrics` sees real build activity, not an empty page.
15
16 /// A build was accepted and fanned out.
17 pub fn build_started() {
18 counter!("bento_builds_total").increment(1);
19 }
20
21 /// A target run reached a terminal state. `status` is `ok` / `failed` /
22 /// `aborted`; `secs` is its wall-clock duration.
23 pub fn target_finished(target: &str, status: &str, secs: f64) {
24 counter!("bento_target_runs_total", "target" => target.to_owned(), "status" => status.to_owned())
25 .increment(1);
26 histogram!("bento_target_run_seconds", "target" => target.to_owned()).record(secs);
27 }
28
29 /// Set the gauge of target tasks currently in flight (the live `active` count).
30 pub fn set_in_flight(n: usize) {
31 gauge!("bento_targets_in_flight").set(n as f64);
32 }
33
34 pub async fn render(State(handle): State<PrometheusHandle>) -> impl IntoResponse {
35 handle.render()
36 }
37
38 /// A render handle that does NOT install the global recorder — the global is a
39 /// process-wide singleton, so tests (many `AppState`s per process) must not
40 /// call [`init`]. Metrics emitted via the macros are dropped under this handle,
41 /// which is fine for tests that only exercise routes.
42 #[cfg(test)]
43 pub fn test_handle() -> PrometheusHandle {
44 PrometheusBuilder::new().build_recorder().handle()
45 }
46