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
//! Prometheus `/metrics` endpoint support (#1391).
//!
//! xberg never installs a [`opentelemetry::global::MeterProvider`] on its own in
//! production code: [`super::metrics::get_metrics`] binds its instruments to whatever
//! provider is global the *first* time anything calls it, via a process-global
//! [`std::sync::OnceLock`], and then never looks again. Left alone, that resolves to the
//! OTel no-op meter, and a `/metrics` endpoint scraping it would return an empty body
//! forever.
//!
//! [`init_prometheus`] installs a real [`opentelemetry_sdk::metrics::SdkMeterProvider`],
//! backed by an [`opentelemetry_prometheus`] exporter, as the global meter provider and
//! hands back the [`prometheus::Registry`] to scrape. It must run before the first call to
//! `get_metrics()` anywhere in the process — see `create_router_with_limits_and_server_config`
//! in `api::router`, which calls it before building the extraction service.
use OnceLock;
use SdkMeterProvider;
use Registry;
/// The process-global Prometheus registry backing every `/metrics` scrape.
static PROMETHEUS_REGISTRY: = new;
/// Install a Prometheus-backed `SdkMeterProvider` as the global OTel meter provider, and
/// return the [`prometheus::Registry`] it feeds.
///
/// Idempotent: only the first call installs the provider. Every later call — including
/// from a different router instance in the same process — returns a clone of the same
/// registry (cheap: [`Registry`] shares its internal state via `Arc`) rather than
/// installing a second, disconnected provider that would silently stop feeding the
/// registry already handed out.
///
/// # When to call this
///
/// Before anything in the process can reach [`super::metrics::get_metrics`]. In practice
/// that means at process start (embedders should call this explicitly) or, as a fallback
/// for callers who only ever use the built-in API server, at the top of
/// `api::create_router_with_limits_and_server_config` — before the extraction service
/// (and therefore the metrics instruments) is built.