init4_bin_base/utils/
metrics.rs

1use crate::utils::from_env::{FromEnv, FromEnvErr, FromEnvVar};
2use metrics_exporter_prometheus::PrometheusBuilder;
3
4use super::from_env::EnvItemInfo;
5
6/// Metrics port env var
7const METRICS_PORT: &str = "METRICS_PORT";
8
9/// Prometheus metrics configuration struct.
10///
11/// Uses the following environment variables:
12/// - `METRICS_PORT` - optional. Defaults to 9000 if missing or unparseable.
13///   The port to bind the metrics server to.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
15#[non_exhaustive]
16#[serde(from = "Option<u16>")]
17pub struct MetricsConfig {
18    /// `METRICS_PORT` - The port on which to bind the metrics server. Defaults
19    /// to `9000` if missing or unparseable.
20    pub port: u16,
21}
22
23impl Default for MetricsConfig {
24    fn default() -> Self {
25        Self { port: 9000 }
26    }
27}
28
29impl From<Option<u16>> for MetricsConfig {
30    fn from(port: Option<u16>) -> Self {
31        Self {
32            port: port.unwrap_or(9000),
33        }
34    }
35}
36
37impl From<u16> for MetricsConfig {
38    fn from(port: u16) -> Self {
39        Self { port }
40    }
41}
42
43impl FromEnv for MetricsConfig {
44    type Error = std::num::ParseIntError;
45
46    fn inventory() -> Vec<&'static EnvItemInfo> {
47        vec![&EnvItemInfo {
48            var: METRICS_PORT,
49            description: "Port on which to serve metrics, u16, defaults to 9000",
50            optional: true,
51        }]
52    }
53
54    fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
55        match u16::from_env_var(METRICS_PORT).map(Self::from) {
56            Ok(cfg) => Ok(cfg),
57            Err(_) => Ok(Self::default()),
58        }
59    }
60}
61
62/// Initialize a [`metrics_exporter_prometheus`] exporter.
63///
64/// Reads the `METRICS_PORT` environment variable to determine the port to bind
65/// the exporter to. If the variable is missing or unparseable, it defaults to
66/// 9000.
67///
68/// See [`MetricsConfig`] for more information.
69///
70/// # Panics
71///
72/// This function will panic if the exporter fails to install, e.g. if the port
73/// is in use.
74pub fn init_metrics() {
75    let cfg = MetricsConfig::from_env().unwrap();
76
77    PrometheusBuilder::new()
78        .with_http_listener(([0, 0, 0, 0], cfg.port))
79        .install()
80        .expect("failed to install prometheus exporter");
81}