1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Process-wide Prometheus metrics plumbing (issue #663, P1c).
//!
//! multimux records metrics throughout the crate via the `metrics` facade's
//! macros (`metrics::counter!`/`gauge!`/`histogram!`):
//!
//! - `multimux_route_up` (`ROUTE_UP`) — gauge, labels `route`: 1.0 while
//! that route's [`crate::route::HealthState`] is `Live`, else 0.0. Set in
//! `origin::supervisor::supervise_driver` alongside every
//! `RouteHandle::set_health` call (the supervisor is the one place that
//! both knows the route name and drives health transitions).
//! - `multimux_source_reconnects_total` (`SOURCE_RECONNECTS_TOTAL`) —
//! counter, labels `route`: bumped once each time a route's supervisor loop
//! re-enters `Reconnecting` (a lost connection or ended attempt about to be
//! retried).
//! - `multimux_active_blocking_requests` (`ACTIVE_BLOCKING_REQUESTS`) —
//! gauge (no route label — the LL-HLS output's blocking-wait helpers don't
//! currently know their own route name; see `output::llhls`): count of
//! LL-HLS blocking-reload/preload-hint requests (RFC 8216bis §6.2.5.2,
//! §6.2.2) currently parked awaiting new data.
//! - `multimux_http_requests_total` / `multimux_http_request_duration_seconds`
//! / `multimux_bytes_served_total` (`HTTP_REQUESTS_TOTAL` /
//! `HTTP_REQUEST_DURATION_SECONDS` / `BYTES_SERVED_TOTAL`) — labels
//! `route`, `path` (and `status` for the requests counter): recorded by
//! `origin`'s HTTP middleware for every request the origin serves, root
//! endpoints (`/metrics`, `/healthz`, `/readyz`) included.
//! - `multimux_parts_produced_total` / `multimux_segments_produced_total`
//! (`PARTS_PRODUCED_TOTAL` / `SEGMENTS_PRODUCED_TOTAL`) — counters, labels
//! `route`: bumped in `crate::source::segment::drive_program_segmenters`,
//! the one place in the driver-backed architecture that actually turns raw
//! samples into parts/segments, labelled by `RouteHandle::name()` (issue
//! #809 — these two counters had no emitter at all since the media-plane
//! port; see that issue and this crate's CHANGELOG for the history: they
//! silently read zero for a while, which is worse than being entirely
//! absent, before being deleted outright pending this fix).
//!
//! Cardinality is bounded on purpose: `route` is either a configured stream
//! name or the fixed token `"unknown"`, and `path` is one of a small fixed
//! set of kinds (`playlist`/`segment`/`part`/`init`/`metrics`/`health`/
//! `other`) — never a raw URI.
//!
//! [`install`] wires a single process-wide `metrics-exporter-prometheus`
//! recorder into the `metrics` facade's global recorder slot and hands back a
//! [`PrometheusHandle`] that renders the current snapshot as Prometheus text
//! exposition (served at `GET /metrics` by `origin::router`).
use OnceLock;
use ;
/// Gauge: 1.0 while the labeled route's ingest health is `Live`, else 0.0.
/// Labels: `route`.
pub const ROUTE_UP: &str = "multimux_route_up";
/// Counter: incremented once each time a route's supervisor loop re-enters
/// `Reconnecting`. Labels: `route`.
pub const SOURCE_RECONNECTS_TOTAL: &str = "multimux_source_reconnects_total";
/// Gauge: count of LL-HLS blocking requests (media-playlist blocking reload,
/// or a preload-hinted part fetch) currently parked awaiting new data,
/// process-wide.
pub const ACTIVE_BLOCKING_REQUESTS: &str = "multimux_active_blocking_requests";
/// Counter: total HTTP requests served. Labels: `route`, `path`, `status`.
pub const HTTP_REQUESTS_TOTAL: &str = "multimux_http_requests_total";
/// Histogram: HTTP request duration, in seconds. Labels: `route`, `path`.
pub const HTTP_REQUEST_DURATION_SECONDS: &str = "multimux_http_request_duration_seconds";
/// Counter: total response bytes served. Labels: `route`, `path`.
pub const BYTES_SERVED_TOTAL: &str = "multimux_bytes_served_total";
/// Counter: total LL-HLS parts published into a route's `Trunk` by
/// `crate::source::segment::drive_program_segmenters`. Labels: `route`
/// (issue #809).
pub const PARTS_PRODUCED_TOTAL: &str = "multimux_parts_produced_total";
/// Counter: total segments published into a route's `Trunk` by
/// `crate::source::segment::drive_program_segmenters`. Labels: `route`
/// (issue #809).
pub const SEGMENTS_PRODUCED_TOTAL: &str = "multimux_segments_produced_total";
static HANDLE: = new;
/// Install the process-wide Prometheus recorder exactly once, returning a
/// clone of its handle on every call.
///
/// `metrics::set_global_recorder` can only succeed the *first* time it's called
/// in a process — every subsequent attempt errors. Every
/// [`crate::origin::AppState`] constructed in the same process (including many
/// independent `#[tokio::test]`s in this crate's own test binary, which all
/// share one process) calls this, so it must be idempotent: the [`OnceLock`]
/// installs the recorder on the first call and every call — first or not — gets
/// a clone of the same [`PrometheusHandle`], reading the one shared,
/// process-wide set of metrics.
///
/// Uses `build_recorder()` + `metrics::set_global_recorder` rather than
/// `PrometheusBuilder::install_recorder()`: the latter spawns a background
/// **upkeep thread** (non-daemon) that never exits, which keeps every process
/// alive and makes `cargo nextest` (one process per test) time out on *every*
/// test in this binary — including the pure-sync store tests. `build_recorder`
/// installs no thread; we don't need periodic upkeep for a scrape-rendered
/// exposition.