pub trait Metrics:
Clone
+ Send
+ Sync
+ 'static {
// Required methods
fn label(&self) -> String;
fn with_label(&self, label: &str) -> Self;
fn with_attribute(&self, key: &str, value: impl Display) -> Self;
fn register<N: Into<String>, H: Into<String>>(
&self,
name: N,
help: H,
metric: impl Metric,
);
fn encode(&self) -> String;
// Provided method
fn scoped_label(&self, label: &str) -> String { ... }
}Expand description
Interface to register and encode metrics.
Required Methods§
Sourcefn with_label(&self, label: &str) -> Self
fn with_label(&self, label: &str) -> Self
Create a new instance of Metrics with the given label appended to the end
of the current Metrics label.
This is commonly used to create a nested context for register.
Labels must start with [a-zA-Z] and contain only [a-zA-Z0-9_]. It is not permitted for
any implementation to use METRICS_PREFIX as the start of a label (reserved for metrics for the runtime).
Sourcefn with_attribute(&self, key: &str, value: impl Display) -> Self
fn with_attribute(&self, key: &str, value: impl Display) -> Self
Create a new instance of Metrics with an additional attribute (key-value pair) applied
to all metrics registered in this context and any child contexts.
Unlike Metrics::with_label which affects the metric name prefix, with_attribute adds
a key-value pair that appears as a separate dimension in the metric output. This is
useful for instrumenting n-ary data structures in a way that is easy to manage downstream.
Keys must start with [a-zA-Z] and contain only [a-zA-Z0-9_]. Values can be any string.
§Labeling Children
Attributes apply to the entire subtree of contexts. When you call with_attribute, the
label is automatically added to all metrics registered in that context and any child
contexts created via with_label:
context
|-- with_label("orchestrator")
|-- with_attribute("epoch", "5")
|-- counter: votes -> orchestrator_votes{epoch="5"}
|-- counter: proposals -> orchestrator_proposals{epoch="5"}
|-- with_label("engine")
|-- gauge: height -> orchestrator_engine_height{epoch="5"}This pattern avoids wrapping every metric in a Family and avoids polluting metric
names with dynamic values like orchestrator_epoch_5_votes.
Using attributes does not reduce cardinality (N epochs still means N time series). Attributes just make metrics easier to query, filter, and aggregate.
§Family Label Conflicts
When using Family metrics, avoid using attribute keys that match the Family’s label field names.
If a conflict occurs, the encoded output will contain duplicate labels (e.g., {env="prod",env="staging"}),
which is invalid Prometheus format and may cause scraping issues.
#[derive(EncodeLabelSet)]
struct Labels { env: String }
// BAD: attribute "env" conflicts with Family field "env"
let ctx = context.with_attribute("env", "prod");
let family: Family<Labels, Counter> = Family::default();
ctx.register("requests", "help", family);
// Produces invalid: requests_total{env="prod",env="staging"}
// GOOD: use distinct names
let ctx = context.with_attribute("region", "us_east");
// Produces valid: requests_total{region="us_east",env="staging"}§Example
// Instead of creating epoch-specific metric names:
let ctx = context.with_label(&format!("consensus_engine_{}", epoch));
// Produces: consensus_engine_5_votes_total, consensus_engine_6_votes_total, ...
// Use attributes to add epoch as a label dimension:
let ctx = context.with_label("consensus_engine").with_attribute("epoch", epoch);
// Produces: consensus_engine_votes_total{epoch="5"}, consensus_engine_votes_total{epoch="6"}, ...Multiple attributes can be chained:
let ctx = context
.with_label("engine")
.with_attribute("region", "us_east")
.with_attribute("instance", "i1");
// Produces: engine_requests_total{region="us_east",instance="i1"} 42§Querying The Latest Attribute
To query the latest attribute value dynamically, create a gauge to track the current value:
// Create a gauge to track the current epoch
let latest_epoch = Gauge::<i64>::default();
context.with_label("orchestrator").register("latest_epoch", "current epoch", latest_epoch.clone());
latest_epoch.set(current_epoch);
// Produces: orchestrator_latest_epoch 5Then create a dashboard variable $latest_epoch with query max(orchestrator_latest_epoch)
and use it in panel queries: consensus_engine_votes_total{epoch="$latest_epoch"}
Sourcefn register<N: Into<String>, H: Into<String>>(
&self,
name: N,
help: H,
metric: impl Metric,
)
fn register<N: Into<String>, H: Into<String>>( &self, name: N, help: H, metric: impl Metric, )
Register a metric with the runtime.
Any registered metric will include (as a prefix) the label of the current context.
Names must start with [a-zA-Z] and contain only [a-zA-Z0-9_].
Sourcefn encode(&self) -> String
fn encode(&self) -> String
Encode all metrics into a buffer.
To ensure downstream analytics tools work correctly, users must never duplicate metrics
(via the concatenation of nested with_label and register calls). This can be avoided
by using with_label to create new context instances (ensures all context instances are
namespaced).
Provided Methods§
Sourcefn scoped_label(&self, label: &str) -> String
fn scoped_label(&self, label: &str) -> String
Prefix the given label with the current context’s label.
Unlike with_label, this method does not create a new context.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.