#[static_metrics]Expand description
Defines a container struct of statically defined metrics.
Applied to a struct whose fields are metric handles, this generates the registration, accessors, and metadata for
the whole group. It is re-exported (and intended to be used) as saluki_metrics::static_metrics.
Because it can rewrite field storage (see “Mapped metrics” below), it must appear before any #[derive(...)]
on the struct.
§Fields
Every field must be typed as Counter, Gauge, or Histogram (from the metrics crate, re-exported by
saluki-metrics). Each field becomes one registered metric whose name is "<prefix>_<field_name>".
§Arguments
prefix = <ident>(required): a bare identifier prefixed to every metric name, for exampleprefix = cache.labels(a, b, ...)(optional): the names of labels applied to every metric in the group. The label values are supplied to the generatednew()and may be of any type implementingsaluki_metrics::Stringable.
§Field attributes
#[metric(level = info | debug | trace)](optional, defaultinfo): the metric’s verbosity level.#[metric(mapped(...))](optional): see below.
§Generated code
For a struct Foo, this generates Foo::new(<label>, ...) -> Foo (generic over each label value’s type), a
Foo::<field>(&self) -> &<Handle> accessor per metric, a Foo::<field>_name() -> &'static str helper, and a
Debug implementation that prints only the struct name. Clone is not generated; derive it directly where needed.
§Mapped metrics
A field can be mapped by one or more labels whose values are supplied at emission time rather than at construction:
#[static_metrics(prefix = component, labels(component_id))]
#[derive(Clone)]
struct Metrics {
events_sent_total: Counter,
// one label, sourced from any `Stringable`:
#[metric(mapped(reason))]
events_discarded_total: Counter,
// or pinned to a concrete type for misuse resistance (and, potentially, cheaper conversion):
#[metric(mapped(reason: DiscardReason))]
other_total: Counter,
}A mapped field’s storage is rewritten to hold a concurrent map of the dynamic label values to lazily registered
handles (the source keeps writing Counter/Gauge/Histogram). Its accessor accepts each label value either by
value or by reference and returns an owned handle. A typed label still only accepts its concrete type (or a
reference to it), so lightweight Copy values can be passed directly without borrowing:
// bare label -> generic `Stringable` parameter; typed label -> `Borrow<T>`, so `T` or `&T` are both accepted
metrics.events_discarded_total("queue_full").increment(1);
metrics.other_total(DiscardReason::QueueFull).increment(1);
metrics.other_total(&DiscardReason::QueueFull).increment(1);Each mapped handle is registered with the fixed struct labels plus the mapped labels. One or many labels may be given, comma-separated, mixing bare and typed forms.