#[cfg(feature = "metrics")]
use metrics_exporter_prometheus::{BuildError, PrometheusBuilder};
#[cfg(feature = "metrics")]
pub(crate) struct MetricsGuard {
handle: tokio::task::JoinHandle<Result<(), String>>,
}
#[cfg(feature = "metrics")]
impl Drop for MetricsGuard {
fn drop(&mut self) {
self.handle.abort();
}
}
#[cfg(not(feature = "metrics"))]
pub(crate) struct MetricsGuard {}
#[cfg(feature = "metrics")]
pub(crate) fn init_metrics_prometheus(port: u16) -> Result<MetricsGuard, BuildError> {
std::net::TcpListener::bind(("0.0.0.0", port)).map_err(|_| {
BuildError::FailedToCreateHTTPListener(format!(
"Metrics port {port} is already in use. Change the port with OXEN_METRICS_PORT="
))
})?;
let (prom_recorder, prom_exporter_fut) = PrometheusBuilder::new()
.with_http_listener(([0, 0, 0, 0], port))
.build()?;
metrics::set_global_recorder(prom_recorder)?;
let handle = tokio::spawn(async move {
prom_exporter_fut.await.map_err(|e| {
let msg = format!("{e:?}");
tracing::error!("Prometheus metrics exporter failed: {msg}");
msg
})
});
Ok(MetricsGuard { handle })
}