From 6ceb3f97503566a47f3bbe6ccfaab7e296848fe7 Mon Sep 17 00:00:00 2001 From: Richard Janis Goldschmidt Date: Tue, 14 May 2024 15:28:40 +0200 Subject: [PATCH] feat(telemetry): register metrics via callback (#1062) ## Summary Register metrics for a service through a callback on the telemetry builder. ## Background `astria_telemetry::Config` should be the central entry point to configure telemetry and metrics. Before this patch the metrics provider, buckets, and global labels were set through config, but actual metrics specific outside of it. With this patch this is done in one step. ## Changes - add `Config::register_metrics` on telemetry builder - change all services to pass their initialization function to it. ## Testing Must be observed in a dev cluster. --- crates/astria-composer/src/main.rs | 5 ++--- crates/astria-conductor/src/main.rs | 3 ++- crates/astria-sequencer-relayer/src/main.rs | 4 ++-- crates/astria-sequencer/src/main.rs | 4 ++-- crates/astria-telemetry/src/lib.rs | 25 +++++++++++++++++++++ 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/crates/astria-composer/src/main.rs b/crates/astria-composer/src/main.rs index 4cbff824a..0dea447e6 100644 --- a/crates/astria-composer/src/main.rs +++ b/crates/astria-composer/src/main.rs @@ -38,11 +38,10 @@ async fn main() -> ExitCode { if !cfg.no_metrics { telemetry_conf = telemetry_conf .metrics_addr(&cfg.metrics_http_listener_addr) - .service_name(env!("CARGO_PKG_NAME")); + .service_name(env!("CARGO_PKG_NAME")) + .register_metrics(metrics_init::register); } - metrics_init::register(); - if let Err(e) = telemetry_conf .try_init() .wrap_err("failed to setup telemetry") diff --git a/crates/astria-conductor/src/main.rs b/crates/astria-conductor/src/main.rs index ee4e78a6f..c96d907ef 100644 --- a/crates/astria-conductor/src/main.rs +++ b/crates/astria-conductor/src/main.rs @@ -45,7 +45,8 @@ async fn main() -> ExitCode { if !cfg.no_metrics { telemetry_conf = telemetry_conf .metrics_addr(&cfg.metrics_http_listener_addr) - .service_name(env!("CARGO_PKG_NAME")); + .service_name(env!("CARGO_PKG_NAME")) + .register_metrics(|| {}); // conductor currently has no metrics } if let Err(e) = telemetry_conf diff --git a/crates/astria-sequencer-relayer/src/main.rs b/crates/astria-sequencer-relayer/src/main.rs index fde982f4d..b5e3dab8b 100644 --- a/crates/astria-sequencer-relayer/src/main.rs +++ b/crates/astria-sequencer-relayer/src/main.rs @@ -35,9 +35,9 @@ async fn main() -> ExitCode { if !cfg.no_metrics { telemetry_conf = telemetry_conf .metrics_addr(&cfg.metrics_http_listener_addr) - .service_name(env!("CARGO_PKG_NAME")); + .service_name(env!("CARGO_PKG_NAME")) + .register_metrics(metrics_init::register); } - metrics_init::register(); if let Err(e) = telemetry_conf .try_init() diff --git a/crates/astria-sequencer/src/main.rs b/crates/astria-sequencer/src/main.rs index a233ae81a..a89f003c5 100644 --- a/crates/astria-sequencer/src/main.rs +++ b/crates/astria-sequencer/src/main.rs @@ -36,9 +36,9 @@ async fn main() -> ExitCode { if !cfg.no_metrics { telemetry_conf = telemetry_conf .metrics_addr(&cfg.metrics_http_listener_addr) - .service_name(env!("CARGO_PKG_NAME")); + .service_name(env!("CARGO_PKG_NAME")) + .register_metrics(metrics_init::register); } - metrics_init::register(); if let Err(e) = telemetry_conf .try_init() diff --git a/crates/astria-telemetry/src/lib.rs b/crates/astria-telemetry/src/lib.rs index b3e82d360..fd3268920 100644 --- a/crates/astria-telemetry/src/lib.rs +++ b/crates/astria-telemetry/src/lib.rs @@ -74,6 +74,10 @@ impl Error { fn exporter_install(source: BuildError) -> Self { Self(ErrorKind::ExporterInstall(source)) } + + fn no_metric_register_func() -> Self { + Self(ErrorKind::NoMetricRegisterFunc) + } } #[derive(Debug, thiserror::Error)] @@ -90,6 +94,11 @@ enum ErrorKind { BucketError(#[source] BuildError), #[error("failed installing prometheus metrics exporter")] ExporterInstall(#[source] BuildError), + #[error( + "telemetry was configured to run with metrics, but no function/closure to register \ + metrics was provided" + )] + NoMetricRegisterFunc, } #[must_use = "the otel config must be initialized to be useful"] @@ -136,6 +145,7 @@ pub struct Config { metrics_addr: Option, service_name: String, metric_buckets: Option>, + register_metrics: Option>, } impl Config { @@ -150,6 +160,7 @@ impl Config { metrics_addr: None, service_name: String::new(), metric_buckets: None, + register_metrics: None, } } } @@ -237,6 +248,14 @@ impl Config { } } + #[must_use = "telemetry must be initialized to be useful"] + pub fn register_metrics(self, f: F) -> Self { + Self { + register_metrics: Some(Box::new(f)), + ..self + } + } + /// Initialize telemetry, consuming the config. /// /// # Errors @@ -252,6 +271,7 @@ impl Config { metrics_addr, service_name, metric_buckets, + register_metrics, } = self; let env_filter = { @@ -322,6 +342,11 @@ impl Config { .map_err(Error::bucket_error)?; } + let Some(register_metrics) = register_metrics else { + return Err(Error::no_metric_register_func()); + }; + register_metrics(); + metrics_builder.install().map_err(Error::exporter_install)?; }