From 19e675400a55defd4f23e18797667c5ade224909 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 13 Jan 2026 21:24:21 -0500 Subject: [PATCH] chore(cli-utils): metrics args --- crates/shared/cli-utils/Cargo.toml | 2 +- crates/shared/cli-utils/src/args.rs | 7 +- crates/shared/cli-utils/src/lib.rs | 13 +-- crates/shared/cli-utils/src/metrics.rs | 117 +++++++++++++++++++++++++ crates/shared/cli-utils/src/tracing.rs | 7 ++ 5 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 crates/shared/cli-utils/src/metrics.rs diff --git a/crates/shared/cli-utils/Cargo.toml b/crates/shared/cli-utils/Cargo.toml index da64b7fa..25de68ee 100644 --- a/crates/shared/cli-utils/Cargo.toml +++ b/crates/shared/cli-utils/Cargo.toml @@ -27,9 +27,9 @@ kona-registry.workspace = true # Tracing tracing.workspace = true +reth-node-core.workspace = true tracing-appender.workspace = true tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "json", "tracing-log"] } -reth-node-core.workspace = true # Metrics metrics-process = { workspace = true, features = ["metrics-rs"] } diff --git a/crates/shared/cli-utils/src/args.rs b/crates/shared/cli-utils/src/args.rs index 4e147400..a7847e9f 100644 --- a/crates/shared/cli-utils/src/args.rs +++ b/crates/shared/cli-utils/src/args.rs @@ -7,7 +7,8 @@ use clap::{ArgAction, Parser}; use kona_registry::OPCHAINS; use crate::{ - FileLogConfig, LogConfig, LogFormat, LogRotation, StdoutLogConfig, verbosity_to_level_filter, + FileLogConfig, LogConfig, LogFormat, LogRotation, MetricsArgs, StdoutLogConfig, + verbosity_to_level_filter, }; /// Log-related CLI arguments. @@ -98,6 +99,10 @@ pub struct GlobalArgs { /// Logging configuration. #[command(flatten)] pub logging: LogArgs, + + /// Prometheus CLI arguments. + #[command(flatten)] + pub metrics: MetricsArgs, } impl GlobalArgs { diff --git a/crates/shared/cli-utils/src/lib.rs b/crates/shared/cli-utils/src/lib.rs index 2563d895..fdba8c1d 100644 --- a/crates/shared/cli-utils/src/lib.rs +++ b/crates/shared/cli-utils/src/lib.rs @@ -9,12 +9,18 @@ pub use sigsegv::SigsegvHandler; mod backtrace; pub use backtrace::Backtracing; -mod args; -pub use args::{GlobalArgs, LogArgs}; +mod metrics; +pub use metrics::MetricsArgs; mod prometheus; pub use prometheus::PrometheusServer; +mod args; +pub use args::{GlobalArgs, LogArgs}; + +mod styles; +pub use styles::CliStyles; + mod logging; pub use logging::{ FileLogConfig, LogConfig, LogFormat, LogRotation, StdoutLogConfig, verbosity_to_level_filter, @@ -28,6 +34,3 @@ pub use version::Version; mod runtime; pub use runtime::RuntimeManager; - -mod styles; -pub use styles::CliStyles; diff --git a/crates/shared/cli-utils/src/metrics.rs b/crates/shared/cli-utils/src/metrics.rs new file mode 100644 index 00000000..b0f38fb5 --- /dev/null +++ b/crates/shared/cli-utils/src/metrics.rs @@ -0,0 +1,117 @@ +//! Utility module to house implementation and declaration of MetricsArgs since it's being used in +//! multiple places, it's just being referenced from this module. + +use std::net::IpAddr; + +use clap::Parser; + +use crate::PrometheusServer; + +/// Configuration for Prometheus metrics. +#[derive(Debug, Clone, Parser)] +#[command(next_help_heading = "Metrics")] +pub struct MetricsArgs { + /// Controls whether Prometheus metrics are enabled. Disabled by default. + #[arg( + long = "metrics.enabled", + global = true, + default_value_t = false, + env = "KONA_METRICS_ENABLED" + )] + pub enabled: bool, + + /// The port to serve Prometheus metrics on. + #[arg(long = "metrics.port", global = true, default_value = "9090", env = "KONA_METRICS_PORT")] + pub port: u16, + + /// The IP address to use for Prometheus metrics. + #[arg( + long = "metrics.addr", + global = true, + default_value = "0.0.0.0", + env = "KONA_METRICS_ADDR" + )] + pub addr: IpAddr, +} + +impl Default for MetricsArgs { + fn default() -> Self { + Self::parse_from::<[_; 0], &str>([]) + } +} + +impl MetricsArgs { + /// Initialize the Prometheus metrics recorder. + /// + /// This function should be called at the beginning of the program. + pub fn init(&self) -> Result<(), metrics_exporter_prometheus::BuildError> { + if self.enabled { + PrometheusServer::init(self.addr, self.port, None)?; + } + + Ok(()) + } + + /// Initialize the Prometheus metrics recorder and run a callback to initialize + /// subsystem-specific metrics if metrics are enabled. + /// + /// This function should be called at the beginning of the program. + pub fn init_with(&self, f: F) -> Result<(), metrics_exporter_prometheus::BuildError> + where + F: FnOnce(), + { + if self.enabled { + PrometheusServer::init(self.addr, self.port, None)?; + f(); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::net::{IpAddr, Ipv4Addr}; + + use clap::Parser; + + use super::*; + + /// Helper struct to parse MetricsArgs within a test CLI structure. + #[derive(Parser, Debug)] + struct TestCli { + #[command(flatten)] + metrics: MetricsArgs, + } + + #[test] + fn test_default_metrics_args() { + let cli = TestCli::parse_from(["test_app"]); + assert!(!cli.metrics.enabled, "Default for metrics.enabled should be false."); + assert_eq!(cli.metrics.port, 9090, "Default for metrics.port should be 9090."); + assert_eq!( + cli.metrics.addr, + IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), + "Default for metrics.addr should be 0.0.0.0." + ); + } + + #[test] + fn test_metrics_args_from_cli() { + let cli = TestCli::parse_from([ + "test_app", + "--metrics.enabled", + "--metrics.port", + "9999", + "--metrics.addr", + "127.0.0.1", + ]); + assert!(cli.metrics.enabled, "metrics.enabled should be true."); + assert_eq!(cli.metrics.port, 9999, "metrics.port should be parsed from CLI."); + assert_eq!( + cli.metrics.addr, + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + "metrics.addr should be parsed from CLI." + ); + } +} diff --git a/crates/shared/cli-utils/src/tracing.rs b/crates/shared/cli-utils/src/tracing.rs index e93e9357..6c10b032 100644 --- a/crates/shared/cli-utils/src/tracing.rs +++ b/crates/shared/cli-utils/src/tracing.rs @@ -78,6 +78,13 @@ impl LogConfig { let filter = EnvFilter::builder().with_default_directive(self.global_level.into()).from_env_lossy(); + self.init_tracing_subscriber_with_filter(filter) + } + + /// Initialize the tracing subscriber with a custom filter. + /// + /// This sets the global default subscriber. Should only be called once. + pub fn init_tracing_subscriber_with_filter(&self, filter: EnvFilter) -> eyre::Result<()> { let registry = tracing_subscriber::registry().with(filter); // Build stdout layer