From f20275502c0675b070b15cf3e4a805694bbb4fb2 Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Mon, 17 Aug 2026 16:34:04 -0300 Subject: [PATCH 1/9] feat: adding metrics-rs/metrics for better metrics handling, also adding point-in-time to some metrics --- Cargo.lock | 63 +++++++++++++ Cargo.toml | 4 +- src/eth/rpc/middleware/rpc_middleware.rs | 2 + src/eth/rpc/server.rs | 19 +++- src/infra/metrics/metrics_config.rs | 115 ++++++++++++++++++++++- src/infra/tracing/tracing_config.rs | 26 ++++- 6 files changed, 216 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45059a03d..02c8f6f0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2256,6 +2256,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + [[package]] name = "enum-ordinalize" version = "4.3.0" @@ -3780,6 +3786,12 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "lockfree-object-pool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + [[package]] name = "log" version = "0.4.29" @@ -3878,17 +3890,38 @@ dependencies = [ "tracing", ] +[[package]] +name = "metrics-tracing-context" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93551ba7648013c25bece467fa087a54dd8dd50a4515182ecf9efb7630b1ed0d" +dependencies = [ + "indexmap 2.14.0", + "itoa", + "lockfree-object-pool", + "metrics", + "metrics-util", + "once_cell", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "metrics-util" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe8db7a05415d0f919ffb905afa37784f71901c9a773188876984b4f769ab986" dependencies = [ + "aho-corasick", "crossbeam-epoch", "crossbeam-utils", "hashbrown 0.15.5", + "indexmap 2.14.0", "metrics", + "ordered-float", "quanta", + "radix_trie", "rand 0.9.4", "rand_xoshiro", "sketches-ddsketch", @@ -3953,6 +3986,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + [[package]] name = "nom" version = "7.1.3" @@ -4307,6 +4349,15 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + [[package]] name = "os_info" version = "3.12.0" @@ -4857,6 +4908,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.8.5" @@ -6583,6 +6644,8 @@ dependencies = [ "log", "metrics", "metrics-exporter-prometheus", + "metrics-tracing-context", + "metrics-util", "nanoid", "nom 8.0.0", "oneshot", diff --git a/Cargo.toml b/Cargo.toml index 440f3ce74..1e071c026 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,8 @@ bytes = "=1.11.1" log = "=0.4.29" metrics = "=0.24.2" metrics-exporter-prometheus = { version = "=0.17.2", optional = true } +metrics-tracing-context = { version = "=0.18.1", optional = true } +metrics-util = { version = "=0.20.0", optional = true } opentelemetry = "=0.31.0" opentelemetry_sdk = { version = "=0.31.0", features = ["rt-tokio"] } opentelemetry-otlp = { version = "=0.31.0", features = [ @@ -225,7 +227,7 @@ dev = [] tools = ["dep:indicatif"] # Enable runtime metrics collection. -metrics = ["dep:metrics-exporter-prometheus"] +metrics = ["dep:metrics-exporter-prometheus", "dep:metrics-tracing-context", "dep:metrics-util"] # Enable runtime rocksdb metrics collection. rocks_metrics = ["metrics"] diff --git a/src/eth/rpc/middleware/rpc_middleware.rs b/src/eth/rpc/middleware/rpc_middleware.rs index 74d4a7e90..b3b2ea090 100644 --- a/src/eth/rpc/middleware/rpc_middleware.rs +++ b/src/eth/rpc/middleware/rpc_middleware.rs @@ -166,6 +166,7 @@ impl RpcServiceT for RpcMiddleware { parent: None, "rpc::request", cid = %new_cid(), + client = field::Empty, rpc_client = field::Empty, rpc_id = field::Empty, rpc_method = field::Empty, @@ -219,6 +220,7 @@ impl RpcServiceT for RpcMiddleware { // trace event Span::with(|s| { + s.rec_str("client", &client); s.rec_str("rpc_id", &request.id); s.rec_str("rpc_client", &client); s.rec_str("rpc_method", &method); diff --git a/src/eth/rpc/server.rs b/src/eth/rpc/server.rs index 1d6e57693..723e40978 100644 --- a/src/eth/rpc/server.rs +++ b/src/eth/rpc/server.rs @@ -1122,7 +1122,13 @@ fn stratus_get_transaction_result(params: Params<'_>, ctx: Arc, ext: fn eth_estimate_gas(params: Params<'_>, ctx: Arc, ext: Extensions) -> Result { // enter span let _middleware_enter = ext.enter_middleware_span(); - let _method_enter = info_span!("rpc::eth_estimateGas", tx_from = field::Empty, tx_to = field::Empty).entered(); + let _method_enter = info_span!( + "rpc::eth_estimateGas", + tx_from = field::Empty, + tx_to = field::Empty, + point_in_time = field::Empty + ) + .entered(); // parse params let (_, call) = next_rpc_param::(params.sequence())?; @@ -1132,6 +1138,7 @@ fn eth_estimate_gas(params: Params<'_>, ctx: Arc, ext: Extensions) - s.rec_opt("tx_from", &call.from); s.rec_opt("tx_to", &call.to); }); + Span::with(|s| s.rec_str("point_in_time", &PointInTime::Latest)); tracing::info!("executing eth_estimateGas"); // execute @@ -1179,6 +1186,7 @@ fn rpc_call(params: Params<'_>, ctx: Arc) -> Result, ctx: Arc) -> Result, ctx: Arc, ext: Extensions) -> Result { // enter span let _middleware_enter = ext.enter_middleware_span(); - let _method_enter = info_span!("rpc::eth_call", tx_from = field::Empty, tx_to = field::Empty, filter = field::Empty).entered(); + let _method_enter = info_span!( + "rpc::eth_call", + tx_from = field::Empty, + tx_to = field::Empty, + filter = field::Empty, + point_in_time = field::Empty + ) + .entered(); match rpc_call(params, ctx) { // result is success diff --git a/src/infra/metrics/metrics_config.rs b/src/infra/metrics/metrics_config.rs index 36319a37b..8821e4d3e 100644 --- a/src/infra/metrics/metrics_config.rs +++ b/src/infra/metrics/metrics_config.rs @@ -1,8 +1,19 @@ use std::net::SocketAddr; -use std::stringify; use clap::Parser; use display_json::DebugAsJson; +#[cfg(feature = "metrics")] +use metrics::KeyName; +#[cfg(feature = "metrics")] +use metrics::Label; +#[cfg(feature = "metrics")] +use metrics_exporter_prometheus::PrometheusBuilder; +#[cfg(feature = "metrics")] +use metrics_tracing_context::LabelFilter; +#[cfg(feature = "metrics")] +use metrics_tracing_context::TracingContextLayer as MetricsTracingContextLayer; +#[cfg(feature = "metrics")] +use metrics_util::layers::Layer as MetricsLayerExt; use crate::infra::metrics::metrics_for_consensus; use crate::infra::metrics::metrics_for_executor; @@ -51,17 +62,111 @@ impl MetricsConfig { #[cfg(feature = "metrics")] fn init_metrics_exporter(address: SocketAddr) { tracing::info!(%address, "creating prometheus metrics exporter"); - if let Err(e) = metrics_exporter_prometheus::PrometheusBuilder::new() + + let builder = PrometheusBuilder::new() .add_global_label("service", crate::infra::build_info::service_name()) .add_global_label("version", crate::infra::build_info::version()) - .with_http_listener(address) - .install() - { + .with_http_listener(address); + + if let Err(e) = install_metrics_tracing_recorder(builder) { tracing::error!(reason = ?e, %address, "failed to create metrics exporter"); } } +#[cfg(feature = "metrics")] +fn install_metrics_tracing_recorder(builder: PrometheusBuilder) -> anyhow::Result<()> { + use std::thread; + use tokio::runtime; + + let recorder = if let Ok(handle) = runtime::Handle::try_current() { + let (recorder, exporter) = { + let _guard = handle.enter(); + builder.build()? + }; + + handle.spawn(exporter); + recorder + } else { + let runtime = runtime::Builder::new_current_thread().enable_all().build()?; + + let (recorder, exporter) = { + let _guard = runtime.enter(); + builder.build()? + }; + + thread::Builder::new() + .name("metrics::exporter".to_string()) + .spawn(move || runtime.block_on(exporter))?; + + recorder + }; + + let recorder = MetricsTracingContextLayer::new(StratusMetricsLabelFilter).layer(recorder); + metrics::set_global_recorder(recorder)?; + + Ok(()) +} + +/// Allowlist for tracing span fields that may be injected as metric labels. +/// +/// Keep this intentionally small: RPC spans contain high-cardinality fields such as ids, +/// parameters, hashes, and addresses that must never become Prometheus labels. +/// Also, please don't use TracingContextLayer::all(). +#[cfg(feature = "metrics")] +#[derive(Clone, Debug)] +struct StratusMetricsLabelFilter; + +#[cfg(feature = "metrics")] +impl LabelFilter for StratusMetricsLabelFilter { + fn should_include_label(&self, name: &KeyName, label: &Label) -> bool { + let metric_name = name.as_str(); + let label_name = label.key(); + + matches!( + (metric_name, label_name), + ( + "stratus_executor_local_call" | "stratus_executor_local_call_account_reads" | "stratus_executor_local_call_slot_reads", + "client" | "rpc_method" | "point_in_time" + ) + ) + } +} + #[cfg(not(feature = "metrics"))] fn init_metrics_exporter(_: SocketAddr) { tracing::info!("creating noop metrics exporter"); } + +#[cfg(all(test, feature = "metrics"))] +mod tests { + use super::*; + + #[test] + fn test_stratus_metrics_label_filter_allows_stable_rpc_context_for_local_call_metrics() { + let filter = StratusMetricsLabelFilter; + let metric = KeyName::from("stratus_executor_local_call"); + + assert!(filter.should_include_label(&metric, &Label::new("client", "other::test-client"))); + assert!(filter.should_include_label(&metric, &Label::new("rpc_method", "eth_call"))); + assert!(filter.should_include_label(&metric, &Label::new("point_in_time", "mined"))); + } + + #[test] + fn test_stratus_metrics_label_filter_rejects_high_cardinality_rpc_context() { + let filter = StratusMetricsLabelFilter; + let metric = KeyName::from("stratus_executor_local_call"); + + assert!(!filter.should_include_label(&metric, &Label::new("rpc_id", "abc123"))); + assert!(!filter.should_include_label(&metric, &Label::new("rpc_params", "[...]"))); + assert!(!filter.should_include_label(&metric, &Label::new("rpc_tx_hash", "0x123"))); + } + + #[test] + fn test_stratus_metrics_label_filter_rejects_context_for_rpc_metrics_with_explicit_client_label() { + let filter = StratusMetricsLabelFilter; + let metric = KeyName::from("stratus_rpc_requests_finished"); + + assert!(!filter.should_include_label(&metric, &Label::new("client", "other::test-client"))); + assert!(!filter.should_include_label(&metric, &Label::new("rpc_method", "eth_call"))); + } +} diff --git a/src/infra/tracing/tracing_config.rs b/src/infra/tracing/tracing_config.rs index 2e888eded..309f17af2 100644 --- a/src/infra/tracing/tracing_config.rs +++ b/src/infra/tracing/tracing_config.rs @@ -10,6 +10,8 @@ use http::HeaderMap; use http::header::HeaderName; use http::header::HeaderValue; use itertools::Itertools; +#[cfg(feature = "metrics")] +use metrics_tracing_context::MetricsLayer as MetricsTracingFieldsLayer; use opentelemetry::KeyValue; use opentelemetry::trace::TracerProvider; use opentelemetry_otlp::Protocol; @@ -147,11 +149,25 @@ impl TracingConfig { } }; - tracing_subscriber::registry() - .with(tracing_context_layer) - .with(stdout_layer) - .with(opentelemetry_layer) - .with(sentry_layer) + #[cfg(feature = "metrics")] + { + println!("tracing registry: enabling metrics tracing context recorder"); + tracing_subscriber::registry() + .with(tracing_context_layer) + .with(MetricsTracingFieldsLayer::new()) + .with(stdout_layer) + .with(opentelemetry_layer) + .with(sentry_layer) + } + + #[cfg(not(feature = "metrics"))] + { + tracing_subscriber::registry() + .with(tracing_context_layer) + .with(stdout_layer) + .with(opentelemetry_layer) + .with(sentry_layer) + } } } From 1825ab933b2889d4151ed24468ad86c18f95753c Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Mon, 17 Aug 2026 16:51:14 -0300 Subject: [PATCH 2/9] style: lint --- src/infra/metrics/metrics_config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/infra/metrics/metrics_config.rs b/src/infra/metrics/metrics_config.rs index 8821e4d3e..e3892e679 100644 --- a/src/infra/metrics/metrics_config.rs +++ b/src/infra/metrics/metrics_config.rs @@ -76,6 +76,7 @@ fn init_metrics_exporter(address: SocketAddr) { #[cfg(feature = "metrics")] fn install_metrics_tracing_recorder(builder: PrometheusBuilder) -> anyhow::Result<()> { use std::thread; + use tokio::runtime; let recorder = if let Ok(handle) = runtime::Handle::try_current() { From c83e13ce7de148cf6db4cf99f4ace4297191f147 Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Mon, 17 Aug 2026 17:07:43 -0300 Subject: [PATCH 3/9] fix: add exemptions for metrics tracing deps --- supply-chain/config.toml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/supply-chain/config.toml b/supply-chain/config.toml index f79aabc82..ffa6260d2 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -540,6 +540,10 @@ criteria = "safe-to-deploy" version = "1.0.0" criteria = "safe-to-deploy" +[[exemptions.endian-type]] +version = "0.1.2" +criteria = "safe-to-deploy" + [[exemptions.enum-ordinalize]] version = "4.3.0" criteria = "safe-to-deploy" @@ -864,6 +868,10 @@ criteria = "safe-to-deploy" version = "1.1.22" criteria = "safe-to-deploy" +[[exemptions.lockfree-object-pool]] +version = "0.1.6" +criteria = "safe-to-deploy" + [[exemptions.lru-slab]] version = "0.1.2" criteria = "safe-to-deploy" @@ -896,6 +904,10 @@ criteria = "safe-to-deploy" version = "0.17.2" criteria = "safe-to-deploy" +[[exemptions.metrics-tracing-context]] +version = "0.18.1" +criteria = "safe-to-deploy" + [[exemptions.metrics-util]] version = "0.20.0" criteria = "safe-to-deploy" @@ -916,6 +928,10 @@ criteria = "safe-to-deploy" version = "0.4.0" criteria = "safe-to-deploy" +[[exemptions.nibble_vec]] +version = "0.1.0" +criteria = "safe-to-deploy" + [[exemptions.nom]] version = "8.0.0" criteria = "safe-to-deploy" @@ -992,6 +1008,10 @@ criteria = "safe-to-deploy" version = "0.9.109" criteria = "safe-to-deploy" +[[exemptions.ordered-float]] +version = "4.6.0" +criteria = "safe-to-deploy" + [[exemptions.os_info]] version = "3.12.0" criteria = "safe-to-deploy" @@ -1108,6 +1128,10 @@ criteria = "safe-to-deploy" version = "0.7.0" criteria = "safe-to-deploy" +[[exemptions.radix_trie]] +version = "0.2.1" +criteria = "safe-to-deploy" + [[exemptions.rand_xoshiro]] version = "0.7.0" criteria = "safe-to-deploy" From 496a875a5fb05a7c7c292c6951fedbca3296a98d Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Mon, 17 Aug 2026 18:10:32 -0300 Subject: [PATCH 4/9] refactor: initialize exporter inside tokio runtime --- src/globals.rs | 6 ++---- src/infra/metrics/metrics_config.rs | 28 ++-------------------------- src/infra/tracing/tracing_config.rs | 22 ++++++---------------- 3 files changed, 10 insertions(+), 46 deletions(-) diff --git a/src/globals.rs b/src/globals.rs index 0b19cf045..1acb83008 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -68,14 +68,12 @@ where // init tokio let tokio = common.init_tokio_runtime().expect("failed to init tokio runtime"); - // init tracing + // init observability services tokio.block_on(async { common.tracing.init(&common.sentry).expect("failed to init tracing"); + common.metrics.init().expect("failed to init metrics"); }); - // init observability services - common.metrics.init().expect("failed to init metrics"); - // init sentry let sentry_guard = common .sentry diff --git a/src/infra/metrics/metrics_config.rs b/src/infra/metrics/metrics_config.rs index e3892e679..475592136 100644 --- a/src/infra/metrics/metrics_config.rs +++ b/src/infra/metrics/metrics_config.rs @@ -75,32 +75,8 @@ fn init_metrics_exporter(address: SocketAddr) { #[cfg(feature = "metrics")] fn install_metrics_tracing_recorder(builder: PrometheusBuilder) -> anyhow::Result<()> { - use std::thread; - - use tokio::runtime; - - let recorder = if let Ok(handle) = runtime::Handle::try_current() { - let (recorder, exporter) = { - let _guard = handle.enter(); - builder.build()? - }; - - handle.spawn(exporter); - recorder - } else { - let runtime = runtime::Builder::new_current_thread().enable_all().build()?; - - let (recorder, exporter) = { - let _guard = runtime.enter(); - builder.build()? - }; - - thread::Builder::new() - .name("metrics::exporter".to_string()) - .spawn(move || runtime.block_on(exporter))?; - - recorder - }; + let (recorder, exporter) = builder.build()?; + tokio::spawn(exporter); let recorder = MetricsTracingContextLayer::new(StratusMetricsLabelFilter).layer(recorder); metrics::set_global_recorder(recorder)?; diff --git a/src/infra/tracing/tracing_config.rs b/src/infra/tracing/tracing_config.rs index 309f17af2..bb62f0c22 100644 --- a/src/infra/tracing/tracing_config.rs +++ b/src/infra/tracing/tracing_config.rs @@ -149,25 +149,15 @@ impl TracingConfig { } }; + let registry = tracing_subscriber::registry().with(tracing_context_layer); + #[cfg(feature = "metrics")] - { + let registry = { println!("tracing registry: enabling metrics tracing context recorder"); - tracing_subscriber::registry() - .with(tracing_context_layer) - .with(MetricsTracingFieldsLayer::new()) - .with(stdout_layer) - .with(opentelemetry_layer) - .with(sentry_layer) - } + registry.with(MetricsTracingFieldsLayer::new()) + }; - #[cfg(not(feature = "metrics"))] - { - tracing_subscriber::registry() - .with(tracing_context_layer) - .with(stdout_layer) - .with(opentelemetry_layer) - .with(sentry_layer) - } + registry.with(stdout_layer).with(opentelemetry_layer).with(sentry_layer) } } From 8d1192792a6e3762cafd68e7e80a1ce7a72e6239 Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Tue, 18 Aug 2026 10:00:52 -0300 Subject: [PATCH 5/9] refac: removing custom label filter, changing for allow_only --- src/infra/metrics/metrics_config.rs | 67 +---------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/src/infra/metrics/metrics_config.rs b/src/infra/metrics/metrics_config.rs index 475592136..c6ab9c69b 100644 --- a/src/infra/metrics/metrics_config.rs +++ b/src/infra/metrics/metrics_config.rs @@ -3,14 +3,8 @@ use std::net::SocketAddr; use clap::Parser; use display_json::DebugAsJson; #[cfg(feature = "metrics")] -use metrics::KeyName; -#[cfg(feature = "metrics")] -use metrics::Label; -#[cfg(feature = "metrics")] use metrics_exporter_prometheus::PrometheusBuilder; #[cfg(feature = "metrics")] -use metrics_tracing_context::LabelFilter; -#[cfg(feature = "metrics")] use metrics_tracing_context::TracingContextLayer as MetricsTracingContextLayer; #[cfg(feature = "metrics")] use metrics_util::layers::Layer as MetricsLayerExt; @@ -78,72 +72,13 @@ fn install_metrics_tracing_recorder(builder: PrometheusBuilder) -> anyhow::Resul let (recorder, exporter) = builder.build()?; tokio::spawn(exporter); - let recorder = MetricsTracingContextLayer::new(StratusMetricsLabelFilter).layer(recorder); + let recorder = MetricsTracingContextLayer::only_allow(["client", "rpc_method", "point_in_time"]).layer(recorder); metrics::set_global_recorder(recorder)?; Ok(()) } -/// Allowlist for tracing span fields that may be injected as metric labels. -/// -/// Keep this intentionally small: RPC spans contain high-cardinality fields such as ids, -/// parameters, hashes, and addresses that must never become Prometheus labels. -/// Also, please don't use TracingContextLayer::all(). -#[cfg(feature = "metrics")] -#[derive(Clone, Debug)] -struct StratusMetricsLabelFilter; - -#[cfg(feature = "metrics")] -impl LabelFilter for StratusMetricsLabelFilter { - fn should_include_label(&self, name: &KeyName, label: &Label) -> bool { - let metric_name = name.as_str(); - let label_name = label.key(); - - matches!( - (metric_name, label_name), - ( - "stratus_executor_local_call" | "stratus_executor_local_call_account_reads" | "stratus_executor_local_call_slot_reads", - "client" | "rpc_method" | "point_in_time" - ) - ) - } -} - #[cfg(not(feature = "metrics"))] fn init_metrics_exporter(_: SocketAddr) { tracing::info!("creating noop metrics exporter"); } - -#[cfg(all(test, feature = "metrics"))] -mod tests { - use super::*; - - #[test] - fn test_stratus_metrics_label_filter_allows_stable_rpc_context_for_local_call_metrics() { - let filter = StratusMetricsLabelFilter; - let metric = KeyName::from("stratus_executor_local_call"); - - assert!(filter.should_include_label(&metric, &Label::new("client", "other::test-client"))); - assert!(filter.should_include_label(&metric, &Label::new("rpc_method", "eth_call"))); - assert!(filter.should_include_label(&metric, &Label::new("point_in_time", "mined"))); - } - - #[test] - fn test_stratus_metrics_label_filter_rejects_high_cardinality_rpc_context() { - let filter = StratusMetricsLabelFilter; - let metric = KeyName::from("stratus_executor_local_call"); - - assert!(!filter.should_include_label(&metric, &Label::new("rpc_id", "abc123"))); - assert!(!filter.should_include_label(&metric, &Label::new("rpc_params", "[...]"))); - assert!(!filter.should_include_label(&metric, &Label::new("rpc_tx_hash", "0x123"))); - } - - #[test] - fn test_stratus_metrics_label_filter_rejects_context_for_rpc_metrics_with_explicit_client_label() { - let filter = StratusMetricsLabelFilter; - let metric = KeyName::from("stratus_rpc_requests_finished"); - - assert!(!filter.should_include_label(&metric, &Label::new("client", "other::test-client"))); - assert!(!filter.should_include_label(&metric, &Label::new("rpc_method", "eth_call"))); - } -} From 2edfb071c68d206f5194bfc9671bb50be0479c45 Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Tue, 18 Aug 2026 12:04:17 -0300 Subject: [PATCH 6/9] hotfix: changing client to rpc_client --- src/eth/rpc/middleware/rpc_middleware.rs | 2 -- src/infra/metrics/metrics_config.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/eth/rpc/middleware/rpc_middleware.rs b/src/eth/rpc/middleware/rpc_middleware.rs index b3b2ea090..74d4a7e90 100644 --- a/src/eth/rpc/middleware/rpc_middleware.rs +++ b/src/eth/rpc/middleware/rpc_middleware.rs @@ -166,7 +166,6 @@ impl RpcServiceT for RpcMiddleware { parent: None, "rpc::request", cid = %new_cid(), - client = field::Empty, rpc_client = field::Empty, rpc_id = field::Empty, rpc_method = field::Empty, @@ -220,7 +219,6 @@ impl RpcServiceT for RpcMiddleware { // trace event Span::with(|s| { - s.rec_str("client", &client); s.rec_str("rpc_id", &request.id); s.rec_str("rpc_client", &client); s.rec_str("rpc_method", &method); diff --git a/src/infra/metrics/metrics_config.rs b/src/infra/metrics/metrics_config.rs index c6ab9c69b..56a309c56 100644 --- a/src/infra/metrics/metrics_config.rs +++ b/src/infra/metrics/metrics_config.rs @@ -72,7 +72,7 @@ fn install_metrics_tracing_recorder(builder: PrometheusBuilder) -> anyhow::Resul let (recorder, exporter) = builder.build()?; tokio::spawn(exporter); - let recorder = MetricsTracingContextLayer::only_allow(["client", "rpc_method", "point_in_time"]).layer(recorder); + let recorder = MetricsTracingContextLayer::only_allow(["rpc_client", "rpc_method", "point_in_time"]).layer(recorder); metrics::set_global_recorder(recorder)?; Ok(()) From 8f21dd9dab05b163f46d90e47eeaaedfb50552af Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Tue, 18 Aug 2026 14:31:34 -0300 Subject: [PATCH 7/9] fix: better error handling --- src/infra/metrics/metrics_config.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/infra/metrics/metrics_config.rs b/src/infra/metrics/metrics_config.rs index 56a309c56..1cf5ffc06 100644 --- a/src/infra/metrics/metrics_config.rs +++ b/src/infra/metrics/metrics_config.rs @@ -42,7 +42,7 @@ impl MetricsConfig { metrics.extend(metrics_for_kafka()); // init metric exporter - init_metrics_exporter(self.metrics_exporter_address); + init_metrics_exporter(self.metrics_exporter_address)?; // init metric description (always after provider started) for metric in &metrics { @@ -54,7 +54,7 @@ impl MetricsConfig { } #[cfg(feature = "metrics")] -fn init_metrics_exporter(address: SocketAddr) { +fn init_metrics_exporter(address: SocketAddr) -> anyhow::Result<()> { tracing::info!(%address, "creating prometheus metrics exporter"); let builder = PrometheusBuilder::new() @@ -62,9 +62,12 @@ fn init_metrics_exporter(address: SocketAddr) { .add_global_label("version", crate::infra::build_info::version()) .with_http_listener(address); - if let Err(e) = install_metrics_tracing_recorder(builder) { + install_metrics_tracing_recorder(builder).map_err(|e| { tracing::error!(reason = ?e, %address, "failed to create metrics exporter"); - } + e + })?; + + Ok(()) } #[cfg(feature = "metrics")] @@ -79,6 +82,7 @@ fn install_metrics_tracing_recorder(builder: PrometheusBuilder) -> anyhow::Resul } #[cfg(not(feature = "metrics"))] -fn init_metrics_exporter(_: SocketAddr) { +fn init_metrics_exporter(_: SocketAddr) -> anyhow::Result<()> { tracing::info!("creating noop metrics exporter"); + Ok(()) } From 9b2af469c88f5c65da01aef93884c199fb75f341 Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Tue, 18 Aug 2026 14:38:50 -0300 Subject: [PATCH 8/9] fix: removing unecessary tracing --- src/infra/metrics/metrics_config.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/infra/metrics/metrics_config.rs b/src/infra/metrics/metrics_config.rs index 1cf5ffc06..c0df253db 100644 --- a/src/infra/metrics/metrics_config.rs +++ b/src/infra/metrics/metrics_config.rs @@ -62,10 +62,7 @@ fn init_metrics_exporter(address: SocketAddr) -> anyhow::Result<()> { .add_global_label("version", crate::infra::build_info::version()) .with_http_listener(address); - install_metrics_tracing_recorder(builder).map_err(|e| { - tracing::error!(reason = ?e, %address, "failed to create metrics exporter"); - e - })?; + install_metrics_tracing_recorder(builder)?; Ok(()) } From 4178a4528c0b6cd3da966dce7ea87181ccfe1e91 Mon Sep 17 00:00:00 2001 From: gventino-cw Date: Tue, 18 Aug 2026 16:19:07 -0300 Subject: [PATCH 9/9] fix: actions e2e tests --- config/stratus-follower.env.local | 1 + 1 file changed, 1 insertion(+) diff --git a/config/stratus-follower.env.local b/config/stratus-follower.env.local index 05b024ac4..5d6683dec 100644 --- a/config/stratus-follower.env.local +++ b/config/stratus-follower.env.local @@ -1,6 +1,7 @@ RUST_LOG=info,stratus::eth::rpc::rpc_subscriptions::rx=off,stratus::eth::consensus::rx=off,stratus::eth::consensus=off,jsonrpsee-server=debug ADDRESS=0.0.0.0:3001 +METRICS_EXPORTER_ADDRESS=0.0.0.0:9001 CHAIN_ID=2008 EVMS=1