zebrad/components/
metrics.rs

1//! An HTTP endpoint for metrics collection.
2
3#![allow(non_local_definitions)]
4
5use std::net::SocketAddr;
6
7use abscissa_core::{Component, FrameworkError};
8use serde::{Deserialize, Serialize};
9
10/// Abscissa component which runs a metrics endpoint.
11#[derive(Debug, Component)]
12pub struct MetricsEndpoint {}
13
14impl MetricsEndpoint {
15    /// Create the component.
16    #[cfg(feature = "prometheus")]
17    pub fn new(config: &Config) -> Result<Self, FrameworkError> {
18        if let Some(addr) = config.endpoint_addr {
19            info!("Trying to open metrics endpoint at {}...", addr);
20
21            let endpoint_result = metrics_exporter_prometheus::PrometheusBuilder::new()
22                .with_http_listener(addr)
23                .install();
24
25            match endpoint_result {
26                Ok(()) => {
27                    info!("Opened metrics endpoint at {}", addr);
28
29                    // Expose binary metadata to metrics, using a single time series with
30                    // value 1:
31                    //     https://www.robustperception.io/exposing-the-software-version-to-prometheus
32                    metrics::counter!(
33                        format!("{}.build.info", env!("CARGO_PKG_NAME")),
34                        "version" => env!("CARGO_PKG_VERSION")
35                    )
36                    .increment(1);
37                }
38                Err(e) => panic!(
39                    "Opening metrics endpoint listener {addr:?} failed: {e:?}. \
40                     Hint: Check if another zebrad or zcashd process is running. \
41                     Try changing the metrics endpoint_addr in the Zebra config.",
42                ),
43            }
44        }
45
46        Ok(Self {})
47    }
48
49    /// Create the component.
50    #[cfg(not(feature = "prometheus"))]
51    pub fn new(config: &Config) -> Result<Self, FrameworkError> {
52        if let Some(addr) = config.endpoint_addr {
53            warn!(
54                ?addr,
55                "unable to activate configured metrics endpoint: \
56                 enable the 'prometheus' feature when compiling zebrad",
57            );
58        }
59
60        Ok(Self {})
61    }
62}
63
64/// Metrics configuration section.
65#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
66#[serde(deny_unknown_fields, default)]
67pub struct Config {
68    /// The address used for the Prometheus metrics endpoint.
69    ///
70    /// Install Zebra using `cargo install --features=prometheus` to enable this config.
71    ///
72    /// The endpoint is disabled if this is set to `None`.
73    pub endpoint_addr: Option<SocketAddr>,
74}
75
76// we like our default configs to be explicit
77#[allow(unknown_lints)]
78#[allow(clippy::derivable_impls)]
79impl Default for Config {
80    fn default() -> Self {
81        Self {
82            endpoint_addr: None,
83        }
84    }
85}