metrics
+ prometheus
= ❤️
prometheus
backend for metrics
crate.
Motivation
Rust has at least two ecosystems regarding metrics collection:
- One is based on the
prometheus
crate, focusing on delivering metrics to Prometheus (or its drop-in replacements like VictoriaMetrics). It provides a lot of Prometheus-specific capabilities and validates metrics strictly to meet the format used by Prometheus. - Another one is based on the
metrics
crate, being more generic and targeting a wider scope, rather than Prometheus only. It provides a convenient and ergonomic facade, allowing to work with metrics in the very similar way we do work with logs and traces vialog
/tracing
ecosystems (and even supportstracing::Span
s for metrics labels).
As the result, some crates use prometheus
crate for providing their metrics, and another crates do use metrics
crate for that. Furthermore, prometheus
and metrics
crates are designed quite differently, making their composition a non-trivial task. This crate aims to mitigate this gap, allowing to combine both prometheus
and metrics
ecosystems in a single project.
Alternatives
If you're not obligated to deal with prometheus
crate directly or via third-party crates which do use it, consider the metrics-exporter-prometheus
crate, which provides a simple Prometheus backend for metrics
facade, without bringing in the whole prometheus
crate's machinery.
Overview
This crate provides a metrics::Recorder
implementation, allowing to work with a prometheus::Registry
via metrics
facade.
It comes in 3 flavours, allowing to choose the smallest performance overhead depending on a use case:
- Regular
Recorder
, allowing to create new metrics viametrics
facade anytime, without limits. Provides the same overhead of accessing an already registered metric as ametrics::Registry
does:read
-lock on a shardedHashMap
plusArc
cloning. FrozenRecorder
, unable to create new metrics viametrics
facade at all (just no-op in such case). Provides the smallest overhead of accessing an already registered metric: just a regularHashMap
lookup plusArc
cloning.FreezableRecorder
, acting the same way as theRecorder
at first, but being able to.freeze()
and so, becoming aFrozenRecorder
at the end. The overhead of accessing an already registered metric is the same asRecorder
andFrozenRecorder
provide, plusAtomicBool
loading to check whether it has been.freeze()
d.
Not any prometheus
metric is supported, because metrics
crate implies only few of them. This is how the metrics
crate's metrics are mapped onto prometheus
ones:
metrics::Counter
:prometheus::IntCounter
+prometheus::IntCounterVec
metrics::Gauge
:prometheus::Gauge
+prometheus::GaugeVec
metrics::Histogram
:prometheus::Histogram
+prometheus::HistogramVec
prometheus::MetricVec
types are used whenever any labels are specified via metrics
facade.
To satisfy the metrics::Recorder
's requirement of allowing changing metrics description anytime after its registration (prometheus
crate doesn't imply and allow that), the Describable
wrapper is used, allowing to arc-swap
the description.
// By default `prometheus::default_registry()` is used.
let recorder = install;
// Either use `metrics` crate interfaces.
increment_counter!;
increment_counter!;
increment_counter!;
// Or construct and provide `prometheus` metrics directly.
recorder.register_metric;
let report = new
.encode_to_string?;
assert_eq!;
// Metrics can be described anytime after being registered in
// `prometheus::Registry`.
describe_counter!;
describe_gauge!;
let report = new
.encode_to_string?;
assert_eq!;
// Description can be changed multiple times and anytime.
describe_counter!;
// Even before a metric is registered in `prometheus::Registry`.
describe_counter!;
increment_counter!;
let report = new
.encode_to_string?;
assert_eq!;
# Ok::
Limitations
Since prometheus
crate validates the metrics format very strictly, not everything, expressed via metrics
facade, may be put into a prometheus::Registry
, ending up with a prometheus::Error
being emitted.
-
Metric names cannot be namespaced with dots (and should follow Prometheus format).
; // panics: 'queries.count' is not a valid metric name increment_counter!; install
-
The same metric should use always the same set of labels:
; increment_counter!; // panics: Inconsistent label cardinality, expect 0 label values, but got 1 increment_counter!; install
; increment_counter!; // panics: label name kind missing in label map increment_counter!; install
; increment_counter!; // panics: Inconsistent label cardinality, expect 1 label values, but got 2 increment_counter!; install
-
The same name cannot be used for different types of metrics:
; increment_counter!; // panics: Duplicate metrics collector registration attempted increment_gauge!; install
-
Any metric registered in a
prometheus::Registry
directly, without usingmetrics
or this crate interfaces, is not usable viametrics
facade and will cause aprometheus::Error
.; default_registry .register?; // panics: Duplicate metrics collector registration attempted increment_gauge!; # Ok:: install
-
metrics::Unit
s are not supported, as Prometheus has no notion of ones. Specifying them viametrics
macros will be no-op.
prometheus::Error
handling
Since metrics::Recorder
doesn't expose any errors in its API, the emitted prometheus::Error
s can be either turned into a panic, or just silently ignored, returning a no-op metric instead (see metrics::Counter::noop()
for example).
This can be tuned by providing a failure::Strategy
when building a Recorder
.
use strategy;
builder
.with_failure_strategy
.build_and_install;
// `prometheus::Error` is ignored inside.
increment_counter!;
let stats = default_registry.gather;
assert_eq!;
The default failure::Strategy
is PanicInDebugNoOpInRelease
. See failure::strategy
module for other available failure::Strategy
s,
or provide your own one by implementing the failure::Strategy
trait.
License
Copyright © 2022 Instrumentisto Team, https://github.com/instrumentisto
This software is subject to the terms of the Blue Oak Model License 1.0.0. If a copy of the BlueOak-1.0.0 license was not distributed with this file, You can obtain one at https://blueoakcouncil.org/license/1.0.0.