|
|
|
@ -4,17 +4,43 @@
|
|
|
|
|
//! implementation. Libraries can use the metrics API provided by this crate, and the consumer of
|
|
|
|
|
//! those libraries can choose the metrics implementation that is most suitable for its use case.
|
|
|
|
|
//!
|
|
|
|
|
//! If no metrics implementation is selected, the facade falls back to a "noop" implementation that
|
|
|
|
|
//! ignores all metrics. The overhead in this case is very small - an atomic load and comparison.
|
|
|
|
|
//! # Overview
|
|
|
|
|
//! `metrics` exposes two main concepts: emitting a metric, and recording it.
|
|
|
|
|
//!
|
|
|
|
|
//! # Use
|
|
|
|
|
//! The basic use of the facade crate is through the three metrics macros: [`counter!`], [`gauge!`],
|
|
|
|
|
//! and [`histogram!`]. These macros correspond to updating a counter, updating a gauge,
|
|
|
|
|
//! and updating a histogram.
|
|
|
|
|
//! ## Emission
|
|
|
|
|
//! Metrics are emitted by utilizing the registration or emission macros. There is a macro for
|
|
|
|
|
//! registering and emitting each fundamental metric type:
|
|
|
|
|
//! - [`register_counter!`] and [`increment_counter!`] for counters
|
|
|
|
|
//! - [`register_gauge!`] and [`update_gauge!`] for gauges
|
|
|
|
|
//! - [`register_histogram!`] and [`record_histogram!`] for histograms
|
|
|
|
|
//!
|
|
|
|
|
//! There is also an [`increment!`] macro, which is shorthand for incrementing a counter by one.
|
|
|
|
|
//!
|
|
|
|
|
//! In order to register or emit a metric, you need a way to record these events, which is where
|
|
|
|
|
//! [`Recorder`] comes into play.
|
|
|
|
|
//!
|
|
|
|
|
//! ## Recording
|
|
|
|
|
//! The [`Recorder`] trait defines the interface between the registration/emission macros, and
|
|
|
|
|
//! exporters, which is we refer to concrete implementations of [`Recorder`]. The trait defines
|
|
|
|
|
//! what the exporters are doing -- recording -- but ultimately exporters are sending data from your
|
|
|
|
|
//! application to somewhere else: whether it be a third-party service or logging via standard out.
|
|
|
|
|
//! It's "exporting" the metric data somewhere else besides your application.
|
|
|
|
|
//!
|
|
|
|
|
//! Each metric type is usually reserved for a specific type of use case, whether it be tracking a
|
|
|
|
|
//! single value or allowing the summation of multiple values, and the respective macros elaborate
|
|
|
|
|
//! more on the usage and invariants provided by each.
|
|
|
|
|
//!
|
|
|
|
|
//! # Getting Started
|
|
|
|
|
//!
|
|
|
|
|
//! ## In libraries
|
|
|
|
|
//! Libraries should link only to the `metrics` crate, and use the provided macros to record
|
|
|
|
|
//! whatever metrics will be useful to downstream consumers.
|
|
|
|
|
//! Libraries need only include the `metrics` crate to emit metrics. When an executable installs a
|
|
|
|
|
//! recorder, all included crates which emitting metrics will now emit their metrics to that record,
|
|
|
|
|
//! which allows library authors to seamless emit their own metrics without knowing or caring which
|
|
|
|
|
//! exporter implementation is chosen, or even if one is installed.
|
|
|
|
|
//!
|
|
|
|
|
//! In cases where no global recorder is installed, a "noop" recorder lives in its place, which has
|
|
|
|
|
//! an incredibly very low overhead: an atomic load and comparison. Libraries can safely instrument
|
|
|
|
|
//! their code without fear of ruining baseline performance.
|
|
|
|
|
//!
|
|
|
|
|
//! ### Examples
|
|
|
|
|
//!
|
|
|
|
@ -38,30 +64,40 @@
|
|
|
|
|
//!
|
|
|
|
|
//! ## In executables
|
|
|
|
|
//!
|
|
|
|
|
//! Executables should choose a metrics implementation and initialize it early in the runtime of
|
|
|
|
|
//! the program. Metrics implementations will typically include a function to do this. Any
|
|
|
|
|
//! metrics recordered before the implementation is initialized will be ignored.
|
|
|
|
|
//! Executables, which themselves can emit their own metrics, are intended to install a global
|
|
|
|
|
//! recorder so that metrics can actually be recorded and exported somewhere.
|
|
|
|
|
//!
|
|
|
|
|
//! The executable itself may use the `metrics` crate to record metrics well.
|
|
|
|
|
//! Initialization of the global recorder isn't required for macros to function, but any metrics
|
|
|
|
|
//! emitted before a global recorder is installed will not be recorded, so early initialization is
|
|
|
|
|
//! recommended when possible.
|
|
|
|
|
//!
|
|
|
|
|
//! ### Warning
|
|
|
|
|
//!
|
|
|
|
|
//! The metrics system may only be initialized once.
|
|
|
|
|
//!
|
|
|
|
|
//! # Available metrics implementations
|
|
|
|
|
//! For most use cases, you'll be using an off-the-shelf exporter implementation that hooks up to an
|
|
|
|
|
//! existing metrics collection system, or interacts with the existing systems/processes that you use.
|
|
|
|
|
//!
|
|
|
|
|
//! * # Native recorder:
|
|
|
|
|
//! * [metrics-exporter-tcp] - outputs metrics to clients over TCP
|
|
|
|
|
//! * [metrics-exporter-prometheus] - serves a Prometheus scrape endpoint
|
|
|
|
|
//! Out of the box, some exporter implementations are available for you to use:
|
|
|
|
|
//!
|
|
|
|
|
//! # Implementing a Recorder
|
|
|
|
|
//! * [metrics-exporter-tcp] - outputs metrics to clients over TCP
|
|
|
|
|
//! * [metrics-exporter-prometheus] - serves a Prometheus scrape endpoint
|
|
|
|
|
//!
|
|
|
|
|
//! Recorders implement the [`Recorder`] trait. Here's a basic example which writes the
|
|
|
|
|
//! metrics in text form via the `log` crate.
|
|
|
|
|
//! You can also implement your own recorder if a suitable one doesn't already exist.
|
|
|
|
|
//!
|
|
|
|
|
//! # Development
|
|
|
|
|
//!
|
|
|
|
|
//! The primary interface with `metrics` is through the [`Recorder`] trait, so we'll show examples
|
|
|
|
|
//! below of the trait and implementation notes.
|
|
|
|
|
//!
|
|
|
|
|
//! ## Implementing and installing a basic recorder
|
|
|
|
|
//!
|
|
|
|
|
//! Here's a basic example which writes metrics in text form via the `log` crate.
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust
|
|
|
|
|
//! use log::info;
|
|
|
|
|
//! use metrics::{Key, Recorder, Unit};
|
|
|
|
|
//! use metrics::SetRecorderError;
|
|
|
|
|
//!
|
|
|
|
|
//! struct LogRecorder;
|
|
|
|
|
//!
|
|
|
|
@ -84,24 +120,9 @@
|
|
|
|
|
//! info!("histogram '{}' -> {}", key, value);
|
|
|
|
|
//! }
|
|
|
|
|
//! }
|
|
|
|
|
//! # fn main() {}
|
|
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! Recorders are installed by calling the [`set_recorder`] function. Recorders should provide a
|
|
|
|
|
//! function that wraps the creation and installation of the recorder:
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust
|
|
|
|
|
//! # use metrics::{Key, Recorder, Unit};
|
|
|
|
|
//! # struct LogRecorder;
|
|
|
|
|
//! # impl Recorder for LogRecorder {
|
|
|
|
|
//! # fn register_counter(&self, _key: Key, _unit: Option<Unit>, _description: Option<&'static str>) {}
|
|
|
|
|
//! # fn register_gauge(&self, _key: Key, _unit: Option<Unit>, _description: Option<&'static str>) {}
|
|
|
|
|
//! # fn register_histogram(&self, _key: Key, _unit: Option<Unit>, _description: Option<&'static str>) {}
|
|
|
|
|
//! # fn increment_counter(&self, _key: Key, _value: u64) {}
|
|
|
|
|
//! # fn update_gauge(&self, _key: Key, _value: f64) {}
|
|
|
|
|
//! # fn record_histogram(&self, _key: Key, _value: u64) {}
|
|
|
|
|
//! # }
|
|
|
|
|
//! use metrics::SetRecorderError;
|
|
|
|
|
//! // Recorders are installed by calling the [`set_recorder`] function. Recorders should provide a
|
|
|
|
|
//! // function that wraps the creation and installation of the recorder:
|
|
|
|
|
//!
|
|
|
|
|
//! static RECORDER: LogRecorder = LogRecorder;
|
|
|
|
|
//!
|
|
|
|
@ -110,36 +131,89 @@
|
|
|
|
|
//! }
|
|
|
|
|
//! # fn main() {}
|
|
|
|
|
//! ```
|
|
|
|
|
//! ## Keys
|
|
|
|
|
//!
|
|
|
|
|
//! # Use with `std`
|
|
|
|
|
//! All metrics are, in essence, the combination of a metric type and metric identifier, such as a
|
|
|
|
|
//! histogram called "response_latency". You could conceivably have multiple metrics with the same
|
|
|
|
|
//! name, so long as they are of different types.
|
|
|
|
|
//!
|
|
|
|
|
//! `set_recorder` requires you to provide a `&'static Recorder`, which can be hard to
|
|
|
|
|
//! obtain if your recorder depends on some runtime configuration. The `set_boxed_recorder`
|
|
|
|
|
//! function is available with the `std` Cargo feature. It is identical to `set_recorder` except
|
|
|
|
|
//! that it takes a `Box<Recorder>` rather than a `&'static Recorder`:
|
|
|
|
|
//! As the types are enforced/limited by the [`Recorder`] trait itself, the remaining piece is the
|
|
|
|
|
//! identifier, which we handle by using [`Key`].
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust
|
|
|
|
|
//! # use metrics::{Key, Recorder, Unit};
|
|
|
|
|
//! # struct LogRecorder;
|
|
|
|
|
//! # impl Recorder for LogRecorder {
|
|
|
|
|
//! # fn register_counter(&self, _key: Key, _unit: Option<Unit>, _description: Option<&'static str>) {}
|
|
|
|
|
//! # fn register_gauge(&self, _key: Key, _unit: Option<Unit>, _description: Option<&'static str>) {}
|
|
|
|
|
//! # fn register_histogram(&self, _key: Key, _unit: Option<Unit>, _description: Option<&'static str>) {}
|
|
|
|
|
//! # fn increment_counter(&self, _key: Key, _value: u64) {}
|
|
|
|
|
//! # fn update_gauge(&self, _key: Key, _value: f64) {}
|
|
|
|
|
//! # fn record_histogram(&self, _key: Key, _value: u64) {}
|
|
|
|
|
//! # }
|
|
|
|
|
//! use metrics::SetRecorderError;
|
|
|
|
|
//! [`Key`] itself is a wrapper for [`KeyData`], which holds not only the name of a metric, but
|
|
|
|
|
//! potentially holds labels for it as well. The name of a metric must always be a literal string.
|
|
|
|
|
//! The labels are a key/value pair, where both components are strings as well.
|
|
|
|
|
//!
|
|
|
|
|
//! # #[cfg(feature = "std")]
|
|
|
|
|
//! pub fn init() -> Result<(), SetRecorderError> {
|
|
|
|
|
//! metrics::set_boxed_recorder(Box::new(LogRecorder))
|
|
|
|
|
//! }
|
|
|
|
|
//! # fn main() {}
|
|
|
|
|
//! ```
|
|
|
|
|
//! Internally, `metrics` uses a clone-on-write "smart pointer" for these values to optimize cases
|
|
|
|
|
//! where the values are static strings, which can provide significant performance benefits. These
|
|
|
|
|
//! smart pointers can also hold owned `String` values, though, so users can mix and match static
|
|
|
|
|
//! strings and owned strings for labels without issue. Metric names, as mentioned above, are always
|
|
|
|
|
//! static strings.
|
|
|
|
|
//!
|
|
|
|
|
//! Two [`Key`] objects can be checked for equality and considered to point to the same metric if
|
|
|
|
|
//! they are equal. Equality checks both the name of the key and the labels of a key. Labels are
|
|
|
|
|
//! _not_ sorted prior to checking for equality, but insertion order is maintained, so any [`Key`]
|
|
|
|
|
//! constructed from the same set of labels in the same order should be equal.
|
|
|
|
|
//!
|
|
|
|
|
//! It is an implementation detail if a recorder wishes to do an deeper equality check that ignores
|
|
|
|
|
//! the order of labels, but practically speaking, metric emission, and thus labels, should be
|
|
|
|
|
//! fixed in ordering in nearly all cases, and so it isn't typically a problem.
|
|
|
|
|
//!
|
|
|
|
|
//! ## Registration
|
|
|
|
|
//!
|
|
|
|
|
//! Recorders must handle the "registration" of a metric.
|
|
|
|
|
//!
|
|
|
|
|
//! In practice, registration solves two potential problems: providing metadata for a metric, and
|
|
|
|
|
//! creating an entry for a metric even though it has not been emitted yet.
|
|
|
|
|
//!
|
|
|
|
|
//! Callers may wish to provide a human-readable description of what the metric is, or provide the
|
|
|
|
|
//! units the metrics uses. Additionally, users may wish to register their metrics so that they
|
|
|
|
|
//! show up in the output of the installed exporter even if the metrics have yet to be emitted.
|
|
|
|
|
//! This allows callers to ensure the metrics output is stable, or allows them to expose all of the
|
|
|
|
|
//! potential metrics a system has to offer, again, even if they have not all yet been emitted.
|
|
|
|
|
//!
|
|
|
|
|
//! As you can see from the trait, the registration methods treats the metadata as optional, and
|
|
|
|
|
//! the macros allow users to mix and match whichever fields they want to provide.
|
|
|
|
|
//!
|
|
|
|
|
//! When a metric is registered, the expectation is that it will show up in output with a default
|
|
|
|
|
//! value, so, for example, a counter should be initialized to zero, a histogram would have no
|
|
|
|
|
//! values, and so on.
|
|
|
|
|
//!
|
|
|
|
|
//! ## Emission
|
|
|
|
|
//!
|
|
|
|
|
//! Likewise, records must handle the emission of metrics as well.
|
|
|
|
|
//!
|
|
|
|
|
//! Comparatively speaking, emission is not too different from registration: you have access to the
|
|
|
|
|
//! same [`Key`] as well as the value being emitted.
|
|
|
|
|
//!
|
|
|
|
|
//! For recorders which temporarily buffer or hold on to values before exporting, a typical approach
|
|
|
|
|
//! would be to utilize atomic variables for the storage. For counters and gauges, this can be done
|
|
|
|
|
//! simply by using types like [`AtomicU64`](std::sync::atomic::AtomicU64). For histograms, this can be
|
|
|
|
|
//! slightly tricky as you must hold on to all of the distinct values. In our helper crate,
|
|
|
|
|
//! [metrics-util], we've provided a type called [AtomicBucket]. For exporters that will want to get
|
|
|
|
|
//! all of the current values in a batch, while clearing the bucket so that values aren't processed
|
|
|
|
|
//! again, [AtomicBucket] provides a simple interface to do so, as well as optimized performance on
|
|
|
|
|
//! both the insertion and read side.
|
|
|
|
|
//!
|
|
|
|
|
//! ## Installing recorders
|
|
|
|
|
//!
|
|
|
|
|
//! In order to actually use an exporter, it must be installed as the "global" recorder. This is a
|
|
|
|
|
//! static recorder that the registration and emission macros refer to behind-the-scenes. `metrics`
|
|
|
|
|
//! provides a few methods to do so: [`set_recorder`], [`set_boxed_recorder`], and [`set_recorder_racy`].
|
|
|
|
|
//!
|
|
|
|
|
//! Primarily, you'll use [`set_boxed_recorder`] to pass a boxed version of the exporter to be
|
|
|
|
|
//! installed. This is due to the fact that most exporters won't be able to be constructed
|
|
|
|
|
//! statically. If you could construct your exporter statically, though, then you could instead
|
|
|
|
|
//! choose [`set_recorder`].
|
|
|
|
|
//!
|
|
|
|
|
//! Similarly, [`set_recorder_racy`] takes a static reference, but is also not thread safe, and
|
|
|
|
|
//! should only be used on platforms which do not support atomic operations, such as embedded
|
|
|
|
|
//! environments.
|
|
|
|
|
//!
|
|
|
|
|
//! [metrics-exporter-tcp]: https://docs.rs/metrics-exporter-tcp
|
|
|
|
|
//! [metrics-exporter-prometheus]: https://docs.rs/metrics-exporter-prometheus
|
|
|
|
|
//! [metrics-util]: https://docs.rs/metrics-util
|
|
|
|
|
//! [AtomicBucket]: https://docs.rs/metrics-util/0.4.0-alpha.6/metrics_util/struct.AtomicBucket.html
|
|
|
|
|
#![deny(missing_docs)]
|
|
|
|
|
use proc_macro_hack::proc_macro_hack;
|
|
|
|
|
|
|
|
|
@ -157,21 +231,29 @@ pub use self::recorder::*;
|
|
|
|
|
|
|
|
|
|
/// Registers a counter.
|
|
|
|
|
///
|
|
|
|
|
/// Counters represent a single value that can only be incremented over time, or reset to zero.
|
|
|
|
|
/// Counters represent a single monotonic value, which means the value can only be incremented, not
|
|
|
|
|
/// decremented, and always starts out with an initial value of zero.
|
|
|
|
|
///
|
|
|
|
|
/// Metrics can be registered with an optional description. Whether or not the installed recorder
|
|
|
|
|
/// does anything with the description is implementation defined. Labels can also be specified
|
|
|
|
|
/// when registering a metric.
|
|
|
|
|
///
|
|
|
|
|
/// Counters, when registered, start at zero.
|
|
|
|
|
/// Metrics can be registered with an optional unit and description. Whether or not the installed
|
|
|
|
|
/// recorder does anything with the description is implementation defined. Labels can also be
|
|
|
|
|
/// specified when registering a metric.
|
|
|
|
|
///
|
|
|
|
|
/// # Scoped versus unscoped
|
|
|
|
|
/// Metrics can be unscoped or scoped, where the scoping is derived by the current module the call
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name.
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name. For example,
|
|
|
|
|
/// take an example metric of "my_counter_metric" being emitted in a binary application "service":
|
|
|
|
|
///
|
|
|
|
|
/// - unscoped: `my_counter_metric`
|
|
|
|
|
/// - scoped: `service.my_counter_metric`
|
|
|
|
|
///
|
|
|
|
|
/// If the metric was emitted in a nested module within the application, the scope would represent
|
|
|
|
|
/// the full module path to where the metric is being emitted, such as
|
|
|
|
|
/// `service.some_module.my_counter_metric`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use metrics::register_counter;
|
|
|
|
|
/// # use metrics::Unit;
|
|
|
|
|
/// # fn main() {
|
|
|
|
|
/// // A regular, unscoped counter:
|
|
|
|
|
/// register_counter!("some_metric_name");
|
|
|
|
@ -179,17 +261,25 @@ pub use self::recorder::*;
|
|
|
|
|
/// // A scoped counter. This inherits a scope derived by the current module:
|
|
|
|
|
/// register_counter!(<"some_metric_name">);
|
|
|
|
|
///
|
|
|
|
|
/// // Providing a unit for a counter:
|
|
|
|
|
/// register_counter!("some_metric_name", Unit::Bytes);
|
|
|
|
|
///
|
|
|
|
|
/// // Providing a description for a counter:
|
|
|
|
|
/// register_counter!("some_metric_name", "number of woopsy daisies");
|
|
|
|
|
/// register_counter!("some_metric_name", "total number of bytes");
|
|
|
|
|
///
|
|
|
|
|
/// // Specifying labels:
|
|
|
|
|
/// register_counter!("some_metric_name", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// register_counter!("some_metric_name", "number of woopsy daisies", "service" => "http");
|
|
|
|
|
/// register_counter!(<"some_metric_name">, "number of woopsy daisies", "service" => "http");
|
|
|
|
|
/// // We can combine the units, description, and labels arbitrarily:
|
|
|
|
|
/// register_counter!("some_metric_name", Unit::Bytes, "total number of bytes");
|
|
|
|
|
/// register_counter!("some_metric_name", Unit::Bytes, "service" => "http");
|
|
|
|
|
/// register_counter!("some_metric_name", "total number of bytes", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And just for an alternative form of passing labels:
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// register_counter!("some_metric_name", Unit::Bytes, "number of woopsy daisies", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// /// We can also pass labels by giving a vector or slice of key/value pairs. In this scenario,
|
|
|
|
|
/// // a unit or description can still be passed in their respective positions:
|
|
|
|
|
/// let dynamic_val = "woo";
|
|
|
|
|
/// let labels = [("dynamic_key", format!("{}!", dynamic_val))];
|
|
|
|
|
/// register_counter!("some_metric_name", &labels);
|
|
|
|
@ -200,21 +290,29 @@ pub use metrics_macros::register_counter;
|
|
|
|
|
|
|
|
|
|
/// Registers a gauge.
|
|
|
|
|
///
|
|
|
|
|
/// Gauges represent a single value that can go up or down over time.
|
|
|
|
|
/// Gauges represent a single value that can go up or down over time, and always starts out with an
|
|
|
|
|
/// initial value of zero.
|
|
|
|
|
///
|
|
|
|
|
/// Metrics can be registered with an optional description. Whether or not the installed recorder
|
|
|
|
|
/// does anything with the description is implementation defined. Labels can also be specified
|
|
|
|
|
/// when registering a metric.
|
|
|
|
|
///
|
|
|
|
|
/// Gauges, when registered, start at zero.
|
|
|
|
|
/// Metrics can be registered with an optional unit and description. Whether or not the installed
|
|
|
|
|
/// recorder does anything with the description is implementation defined. Labels can also be
|
|
|
|
|
/// specified when registering a metric.
|
|
|
|
|
///
|
|
|
|
|
/// # Scoped versus unscoped
|
|
|
|
|
/// Metrics can be unscoped or scoped, where the scoping is derived by the current module the call
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name.
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name. For example,
|
|
|
|
|
/// take an example metric of "my_gauge_metric" being emitted in a binary application "service":
|
|
|
|
|
///
|
|
|
|
|
/// - unscoped: `my_gauge_metric`
|
|
|
|
|
/// - scoped: `service.my_gauge_metric`
|
|
|
|
|
///
|
|
|
|
|
/// If the metric was emitted in a nested module within the application, the scope would represent
|
|
|
|
|
/// the full module path to where the metric is being emitted, such as
|
|
|
|
|
/// `service.some_module.my_gauge_metric`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use metrics::register_gauge;
|
|
|
|
|
/// # use metrics::Unit;
|
|
|
|
|
/// # fn main() {
|
|
|
|
|
/// // A regular, unscoped gauge:
|
|
|
|
|
/// register_gauge!("some_metric_name");
|
|
|
|
@ -222,17 +320,25 @@ pub use metrics_macros::register_counter;
|
|
|
|
|
/// // A scoped gauge. This inherits a scope derived by the current module:
|
|
|
|
|
/// register_gauge!(<"some_metric_name">);
|
|
|
|
|
///
|
|
|
|
|
/// // Providing a unit for a gauge:
|
|
|
|
|
/// register_gauge!("some_metric_name", Unit::Bytes);
|
|
|
|
|
///
|
|
|
|
|
/// // Providing a description for a gauge:
|
|
|
|
|
/// register_gauge!("some_metric_name", "number of woopsy daisies");
|
|
|
|
|
/// register_gauge!("some_metric_name", "total number of bytes");
|
|
|
|
|
///
|
|
|
|
|
/// // Specifying labels:
|
|
|
|
|
/// register_gauge!("some_metric_name", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// register_gauge!("some_metric_name", "number of woopsy daisies", "service" => "http");
|
|
|
|
|
/// register_gauge!(<"some_metric_name">, "number of woopsy daisies", "service" => "http");
|
|
|
|
|
/// // We can combine the units, description, and labels arbitrarily:
|
|
|
|
|
/// register_gauge!("some_metric_name", Unit::Bytes, "total number of bytes");
|
|
|
|
|
/// register_gauge!("some_metric_name", Unit::Bytes, "service" => "http");
|
|
|
|
|
/// register_gauge!("some_metric_name", "total number of bytes", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And just for an alternative form of passing labels:
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// register_gauge!("some_metric_name", Unit::Bytes, "total number of bytes", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario,
|
|
|
|
|
/// // a unit or description can still be passed in their respective positions:
|
|
|
|
|
/// let dynamic_val = "woo";
|
|
|
|
|
/// let labels = [("dynamic_key", format!("{}!", dynamic_val))];
|
|
|
|
|
/// register_gauge!("some_metric_name", &labels);
|
|
|
|
@ -243,21 +349,29 @@ pub use metrics_macros::register_gauge;
|
|
|
|
|
|
|
|
|
|
/// Records a histogram.
|
|
|
|
|
///
|
|
|
|
|
/// Histograms measure the distribution of values for a given set of measurements.
|
|
|
|
|
/// Histograms measure the distribution of values for a given set of measurements, and start with no
|
|
|
|
|
/// initial values.
|
|
|
|
|
///
|
|
|
|
|
/// Metrics can be registered with an optional description. Whether or not the installed recorder
|
|
|
|
|
/// does anything with the description is implementation defined. Labels can also be specified
|
|
|
|
|
/// when registering a metric.
|
|
|
|
|
///
|
|
|
|
|
/// Histograms, when registered, start at zero.
|
|
|
|
|
/// Metrics can be registered with an optional unit and description. Whether or not the installed
|
|
|
|
|
/// recorder does anything with the description is implementation defined. Labels can also be
|
|
|
|
|
/// specified when registering a metric.
|
|
|
|
|
///
|
|
|
|
|
/// # Scoped versus unscoped
|
|
|
|
|
/// Metrics can be unscoped or scoped, where the scoping is derived by the current module the call
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name.
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name. For example,
|
|
|
|
|
/// take an example metric of "my_histogram_metric" being emitted in a binary application "service":
|
|
|
|
|
///
|
|
|
|
|
/// - unscoped: `my_histogram_metric`
|
|
|
|
|
/// - scoped: `service.my_histogram_metric`
|
|
|
|
|
///
|
|
|
|
|
/// If the metric was emitted in a nested module within the application, the scope would represent
|
|
|
|
|
/// the full module path to where the metric is being emitted, such as
|
|
|
|
|
/// `service.some_module.my_histogram_metric`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use metrics::register_histogram;
|
|
|
|
|
/// # use metrics::Unit;
|
|
|
|
|
/// # fn main() {
|
|
|
|
|
/// // A regular, unscoped histogram:
|
|
|
|
|
/// register_histogram!("some_metric_name");
|
|
|
|
@ -265,17 +379,25 @@ pub use metrics_macros::register_gauge;
|
|
|
|
|
/// // A scoped histogram. This inherits a scope derived by the current module:
|
|
|
|
|
/// register_histogram!(<"some_metric_name">);
|
|
|
|
|
///
|
|
|
|
|
/// // Providing a unit for a histogram:
|
|
|
|
|
/// register_histogram!("some_metric_name", Unit::Nanoseconds);
|
|
|
|
|
///
|
|
|
|
|
/// // Providing a description for a histogram:
|
|
|
|
|
/// register_histogram!("some_metric_name", "number of woopsy daisies");
|
|
|
|
|
/// register_histogram!("some_metric_name", "request handler duration");
|
|
|
|
|
///
|
|
|
|
|
/// // Specifying labels:
|
|
|
|
|
/// register_histogram!("some_metric_name", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// register_histogram!("some_metric_name", "number of woopsy daisies", "service" => "http");
|
|
|
|
|
/// register_histogram!(<"some_metric_name">, "number of woopsy daisies", "service" => "http");
|
|
|
|
|
/// // We can combine the units, description, and labels arbitrarily:
|
|
|
|
|
/// register_histogram!("some_metric_name", Unit::Nanoseconds, "request handler duration");
|
|
|
|
|
/// register_histogram!("some_metric_name", Unit::Nanoseconds, "service" => "http");
|
|
|
|
|
/// register_histogram!("some_metric_name", "request handler duration", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And just for an alternative form of passing labels:
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// register_histogram!("some_metric_name", Unit::Nanoseconds, "request handler duration", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario,
|
|
|
|
|
/// // a unit or description can still be passed in their respective positions:
|
|
|
|
|
/// let dynamic_val = "woo";
|
|
|
|
|
/// let labels = [("dynamic_key", format!("{}!", dynamic_val))];
|
|
|
|
|
/// register_histogram!("some_metric_name", &labels);
|
|
|
|
@ -284,13 +406,22 @@ pub use metrics_macros::register_gauge;
|
|
|
|
|
#[proc_macro_hack]
|
|
|
|
|
pub use metrics_macros::register_histogram;
|
|
|
|
|
|
|
|
|
|
/// Increments a counter.
|
|
|
|
|
/// Increments a counter by one.
|
|
|
|
|
///
|
|
|
|
|
/// Counters represent a single value that can only be incremented over time, or reset to zero.
|
|
|
|
|
/// Counters represent a single monotonic value, which means the value can only be incremented, not
|
|
|
|
|
/// decremented, and always starts out with an initial value of zero.
|
|
|
|
|
///
|
|
|
|
|
/// # Scoped versus unscoped
|
|
|
|
|
/// Metrics can be unscoped or scoped, where the scoping is derived by the current module the call
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name.
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name. For example,
|
|
|
|
|
/// take an example metric of "my_counter_metric" being emitted in a binary application "service":
|
|
|
|
|
///
|
|
|
|
|
/// - unscoped: `my_counter_metric`
|
|
|
|
|
/// - scoped: `service.my_counter_metric`
|
|
|
|
|
///
|
|
|
|
|
/// If the metric was emitted in a nested module within the application, the scope would represent
|
|
|
|
|
/// the full module path to where the metric is being emitted, such as
|
|
|
|
|
/// `service.some_module.my_counter_metric`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
@ -305,11 +436,7 @@ pub use metrics_macros::register_histogram;
|
|
|
|
|
/// // Specifying labels:
|
|
|
|
|
/// increment!("some_metric_name", "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// increment!("some_metric_name", "service" => "http");
|
|
|
|
|
/// increment!(<"some_metric_name">, "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And just for an alternative form of passing labels:
|
|
|
|
|
/// // We can also pass labels by giving a vector or slice of key/value pairs:
|
|
|
|
|
/// let dynamic_val = "woo";
|
|
|
|
|
/// let labels = [("dynamic_key", format!("{}!", dynamic_val))];
|
|
|
|
|
/// increment!("some_metric_name", &labels);
|
|
|
|
@ -320,11 +447,20 @@ pub use metrics_macros::increment;
|
|
|
|
|
|
|
|
|
|
/// Increments a counter.
|
|
|
|
|
///
|
|
|
|
|
/// Counters represent a single value that can only be incremented over time, or reset to zero.
|
|
|
|
|
/// Counters represent a single monotonic value, which means the value can only be incremented, not
|
|
|
|
|
/// decremented, and always starts out with an initial value of zero.
|
|
|
|
|
///
|
|
|
|
|
/// # Scoped versus unscoped
|
|
|
|
|
/// Metrics can be unscoped or scoped, where the scoping is derived by the current module the call
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name.
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name. For example,
|
|
|
|
|
/// take an example metric of "my_counter_metric" being emitted in a binary application "service":
|
|
|
|
|
///
|
|
|
|
|
/// - unscoped: `my_counter_metric`
|
|
|
|
|
/// - scoped: `service.my_counter_metric`
|
|
|
|
|
///
|
|
|
|
|
/// If the metric was emitted in a nested module within the application, the scope would represent
|
|
|
|
|
/// the full module path to where the metric is being emitted, such as
|
|
|
|
|
/// `service.some_module.my_counter_metric`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
@ -339,11 +475,7 @@ pub use metrics_macros::increment;
|
|
|
|
|
/// // Specifying labels:
|
|
|
|
|
/// counter!("some_metric_name", 12, "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// counter!("some_metric_name", 12, "service" => "http");
|
|
|
|
|
/// counter!(<"some_metric_name">, 12, "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And just for an alternative form of passing labels:
|
|
|
|
|
/// // We can also pass labels by giving a vector or slice of key/value pairs:
|
|
|
|
|
/// let dynamic_val = "woo";
|
|
|
|
|
/// let labels = [("dynamic_key", format!("{}!", dynamic_val))];
|
|
|
|
|
/// counter!("some_metric_name", 12, &labels);
|
|
|
|
@ -354,11 +486,20 @@ pub use metrics_macros::counter;
|
|
|
|
|
|
|
|
|
|
/// Updates a gauge.
|
|
|
|
|
///
|
|
|
|
|
/// Gauges represent a single value that can go up or down over time.
|
|
|
|
|
/// Gauges represent a single value that can go up or down over time, and always starts out with an
|
|
|
|
|
/// initial value of zero.
|
|
|
|
|
///
|
|
|
|
|
/// # Scoped versus unscoped
|
|
|
|
|
/// Metrics can be unscoped or scoped, where the scoping is derived by the current module the call
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name.
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name. For example,
|
|
|
|
|
/// take an example metric of "my_gauge_metric" being emitted in a binary application "service":
|
|
|
|
|
///
|
|
|
|
|
/// - unscoped: `my_gauge_metric`
|
|
|
|
|
/// - scoped: `service.my_gauge_metric`
|
|
|
|
|
///
|
|
|
|
|
/// If the metric was emitted in a nested module within the application, the scope would represent
|
|
|
|
|
/// the full module path to where the metric is being emitted, such as
|
|
|
|
|
/// `service.some_module.my_gauge_metric`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
@ -373,11 +514,7 @@ pub use metrics_macros::counter;
|
|
|
|
|
/// // Specifying labels:
|
|
|
|
|
/// gauge!("some_metric_name", 66.6666, "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// gauge!("some_metric_name", 55.5555, "service" => "http");
|
|
|
|
|
/// gauge!(<"some_metric_name">, 11.1111, "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And just for an alternative form of passing labels:
|
|
|
|
|
/// // We can also pass labels by giving a vector or slice of key/value pairs:
|
|
|
|
|
/// let dynamic_val = "woo";
|
|
|
|
|
/// let labels = [("dynamic_key", format!("{}!", dynamic_val))];
|
|
|
|
|
/// gauge!("some_metric_name", 42.42, &labels);
|
|
|
|
@ -388,11 +525,20 @@ pub use metrics_macros::gauge;
|
|
|
|
|
|
|
|
|
|
/// Records a histogram.
|
|
|
|
|
///
|
|
|
|
|
/// Histograms measure the distribution of values for a given set of measurements.
|
|
|
|
|
/// Histograms measure the distribution of values for a given set of measurements, and start with no
|
|
|
|
|
/// initial values.
|
|
|
|
|
///
|
|
|
|
|
/// # Scoped versus unscoped
|
|
|
|
|
/// Metrics can be unscoped or scoped, where the scoping is derived by the current module the call
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name.
|
|
|
|
|
/// is taking place in. This scope is used as a prefix to the provided metric name. For example,
|
|
|
|
|
/// take an example metric of "my_histogram_metric" being emitted in a binary application "service":
|
|
|
|
|
///
|
|
|
|
|
/// - unscoped: `my_histogram_metric`
|
|
|
|
|
/// - scoped: `service.my_histogram_metric`
|
|
|
|
|
///
|
|
|
|
|
/// If the metric was emitted in a nested module within the application, the scope would represent
|
|
|
|
|
/// the full module path to where the metric is being emitted, such as
|
|
|
|
|
/// `service.some_module.my_histogram_metric`.
|
|
|
|
|
///
|
|
|
|
|
/// # Implicit conversions
|
|
|
|
|
/// Histograms are represented as `u64` values, but often come from another source, such as a time
|
|
|
|
@ -416,16 +562,11 @@ pub use metrics_macros::gauge;
|
|
|
|
|
///
|
|
|
|
|
/// // A scoped histogram. This inherits a scope derived by the current module:
|
|
|
|
|
/// histogram!(<"some_metric_name">, 38);
|
|
|
|
|
/// histogram!(<"some_metric_name">, d);
|
|
|
|
|
///
|
|
|
|
|
/// // Specifying labels:
|
|
|
|
|
/// histogram!("some_metric_name", 38, "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And all combined:
|
|
|
|
|
/// histogram!("some_metric_name", d, "service" => "http");
|
|
|
|
|
/// histogram!(<"some_metric_name">, 57, "service" => "http");
|
|
|
|
|
///
|
|
|
|
|
/// // And just for an alternative form of passing labels:
|
|
|
|
|
/// // We can also pass labels by giving a vector or slice of key/value pairs:
|
|
|
|
|
/// let dynamic_val = "woo";
|
|
|
|
|
/// let labels = [("dynamic_key", format!("{}!", dynamic_val))];
|
|
|
|
|
/// histogram!("some_metric_name", 1337, &labels);
|
|
|
|
|