feat: populate metric labels from span context using metrics-tracing-context - #2619
feat: populate metric labels from span context using metrics-tracing-context#2619gventino-cw wants to merge 11 commits into
Conversation
…ing point-in-time to some metrics
There was a problem hiding this comment.
Summary
Nice improvement to metrics context propagation. The PR correctly wires metrics-tracing-context into tracing subscriber setup, adds a conservative allowlist (client, rpc_method, point_in_time) to avoid high-cardinality metric labels, and includes focused tests for the filter behavior. I also verified the added RPC span fields (client, point_in_time) are recorded where needed to support those labels.
I did not find concrete correctness, security, or deploy-safety issues in the provided diff.
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Explore these optional code suggestions:
|
There was a problem hiding this comment.
Summary
LGTM. The PR cleanly wires tracing-context-to-metrics propagation with an explicit allowlist, and the added tests cover both positive and negative label-filter behavior (including protection against high-cardinality RPC labels). I also verified the new client and point_in_time span fields are declared and recorded where needed for the intended local-call metrics.
No concrete correctness, security, or deploy-safety issues were identified in the provided diff.
There was a problem hiding this comment.
Summary
Good direction overall: the PR wires tracing context into metrics with a tight allowlist (client, rpc_method, point_in_time) and adds focused tests to prevent high-cardinality leakage. The new RPC span fields also look consistent with the intended metric enrichment.
I found one blocking correctness/deploy-safety issue in metrics initialization.
Blocking
- Metrics exporter startup failures are swallowed, but
MetricsConfig::init()still returnsOk(()).
Ininit_metrics_exporter, errors frominstall_metrics_tracing_recorder(builder)are only logged; meanwhileMetricsConfig::init()cannot observe the failure and proceeds to register metric descriptions as if metrics were active. This can silently boot without metrics in environments expecting them, making observability regressions hard to detect. Please propagate the error up (or explicitly fail startup undermetricsfeature) instead of only logging.
There was a problem hiding this comment.
Summary
Good evolution overall: the PR wires tracing context into metrics with an explicit label allowlist and adds focused tests to avoid high-cardinality leakage.
I found one blocking deploy-safety/correctness issue still present.
Blocking
- Metrics initialization errors are still swallowed, so startup can succeed with metrics silently disabled.
init_metrics_exporterlogs errors frominstall_metrics_tracing_recorder(builder)but returns(), andMetricsConfig::init()always returnsOk(()). With this flow, failures in exporter/recorder setup (e.g., bind error, global recorder already set) won’t fail startup even whenmetricsis enabled, causing silent observability regressions.
Please propagate the error back through init_metrics_exporter/MetricsConfig::init() (or explicitly document/guard a non-fatal policy) so runtime behavior is deterministic.
There was a problem hiding this comment.
Summary
Good progress on wiring tracing context into metrics and moving metrics initialization inside the Tokio runtime. The client and point_in_time span fields are now consistently recorded and the only_allow filter reduces cardinality risk.
I still found one blocking deploy-safety issue.
Blocking
- Metrics exporter/recorder initialization failures are still swallowed, so startup can succeed with metrics silently disabled.
Ininit_metrics_exporter, errors frominstall_metrics_tracing_recorder(builder)are logged but not propagated, andMetricsConfig::init()still returns success. This keeps the previous failure mode where bind/recorder setup errors (including global recorder conflicts) can pass unnoticed in production whenmetricsis enabled.
Please return anyhow::Result<()> from init_metrics_exporter and propagate it through MetricsConfig::init() so startup behavior is deterministic (or explicitly gate/document non-fatal behavior).
carneiro-cw
left a comment
There was a problem hiding this comment.
PointInTime can be MinedPast(number), which has unbounded cardinality. When used for labels we should just record MinedPast, Latest or Pending.
There was a problem hiding this comment.
Summary
Nice evolution overall: tracing fields (rpc_client, point_in_time) are now wired through to metrics context, and metrics init was moved under the Tokio runtime so spawning the exporter is valid. I found one blocking deploy-safety issue still present.
Blocking
- Metrics exporter initialization failures are still swallowed, allowing startup to succeed with metrics silently broken.
install_metrics_tracing_recorder(builder)returnsResult, butinit_metrics_exporterlogs and suppresses errors, andMetricsConfig::init()still returnsOk(())regardless. That keeps non-deterministic boot behavior for bind failures orset_global_recorderconflicts, which is risky in production observability and was the prior blocker.
Please propagate the error path (e.g., make init_metrics_exporter return anyhow::Result<()> and ? it from MetricsConfig::init()) so startup either fully enables metrics or fails explicitly.
We don't need to do it, the PointInTime enum and MinedPointInTime enum impl the /// EVM storage point-in-time indicator.
#[derive(Debug, strum::Display, Clone, Copy, Default, strum::EnumIs, serde::Serialize, PartialEq, Eq)]
#[cfg_attr(test, derive(fake::Dummy))]
pub enum PointInTime {
/// State of `Account` or `Slot` at the pending block being mined.
///
/// If the pending state did not change, then it is the same as the `Mined` state.
#[strum(to_string = "pending")]
Pending,
/// State of `Account` or `Slot` at the last mined block.
#[default]
#[strum(to_string = "mined")]
Latest,
/// State of `Account` or `Slot` at some specific mined block in the past.
#[strum(to_string = "mined-past")]
Past(BlockNumber),
}#[derive(Debug, strum::Display)]
pub enum MinedPointInTime<'a> {
#[strum(to_string = "latest")]
Latest(Seal, Option<RwLockReadGuard<'a, ()>>),
#[strum(to_string = "past")]
Past(Seal, BlockNumber),
} |
There was a problem hiding this comment.
Summary
Looks good overall. The previously blocking deploy-safety issue is addressed: metrics exporter/recorder setup errors are now propagated via anyhow::Result from init_metrics_exporter into MetricsConfig::init, making startup behavior deterministic instead of silently disabling metrics.
I also verified the metrics/tracing context wiring is coherent under the metrics feature:
MetricsLayeris attached to the tracing subscriber (tracing_config.rs) to capture span fields.- Prometheus recorder is wrapped with
TracingContextLayer::only_allow(["rpc_client", "rpc_method", "point_in_time"])to bound label cardinality. point_in_timeis explicitly recorded oneth_call/eth_estimateGasspans inserver.rs.
No concrete blocking issues found in the provided diff context.
There was a problem hiding this comment.
Summary
Looks good to me.
This revision addresses the previous deploy-safety concern by propagating metrics exporter initialization errors (anyhow::Result + ?) instead of swallowing them, and it initializes metrics within the Tokio runtime before spawning the exporter task. The tracing-to-metrics wiring is coherent under the metrics feature (MetricsLayer on the tracing subscriber + TracingContextLayer::only_allow(["rpc_client", "rpc_method", "point_in_time"]) on the recorder), which also bounds label cardinality.
I did not find any new concrete correctness/security/regression issues in the provided diff.
There was a problem hiding this comment.
Summary
LGTM. This revision correctly wires tracing span fields into metrics context under the metrics feature and keeps cardinality bounded via only_allow(["rpc_client", "rpc_method", "point_in_time"]). I also verified the earlier deploy-safety concern is still addressed: metrics exporter initialization now propagates errors (anyhow::Result + ?), and metrics init runs inside the Tokio runtime before tokio::spawn(exporter).
I did not find concrete correctness, security, concurrency, or deploy-safety regressions in the provided diff context.
PR Type
#2579
Enhancement, Tests
Description
instrument RPC spans with
clientandpoint_in_timefieldsadd Prometheus exporter and tracing context recorder
implement
StratusMetricsLabelFilterallowlist with testsDiagram Walkthrough
File Walkthrough
rpc_middleware.rs
Instrument middleware with client fieldsrc/eth/rpc/middleware/rpc_middleware.rs
clientfield to info_span! macroclientvias.rec_strin middlewareserver.rs
Add point_in_time to RPC method spanssrc/eth/rpc/server.rs
point_in_timeineth_estimateGasandeth_callspanspoint_in_timewithSpan::withcallsmetrics_config.rs
Initialize metrics exporter and label filtersrc/infra/metrics/metrics_config.rs
install_metrics_tracing_recorderStratusMetricsLabelFilterallowlist implementationtracing_config.rs
Enable metrics tracing context layersrc/infra/tracing/tracing_config.rs
MetricsTracingFieldsLayerwhen metrics feature activeCargo.toml
Add metrics-tracing-context and util dependenciesCargo.toml
metrics-tracing-contextandmetrics-utiloptional depsmetricsfeature to include new dependencies