prometheus_utils/
lib.rs

1//! Utilities for working with Prometheus metrics in Rust
2//!
3//! This crate builds on the Promtheus crate to provide API with additional safety guardrails:
4//!
5//! * Use [`InstrumentedFuture`] to easily instrument futures with metric updates.
6//! * Use [`GuardedGauge`] to work with gauges using an RAII-style guard that decrements
7//!   the gauge upon drop.
8//! * Use [`IntCounterWithLabels`] and [`IntGaugeWithLabels`] to produce labeled Prometheus
9//!   metrics with a type-safe API.
10
11// When building the project in release mode:
12//   (1): Promote warnings into errors.
13//   (2): Warn about public items that are missing documentation.
14//   (3): Deny broken documentation links.
15//   (4): Deny invalid codeblock attributes in documentation.
16//   (5): Promote warnings in examples into errors, except for unused variables.
17#![cfg_attr(not(debug_assertions), deny(warnings))]
18#![cfg_attr(not(debug_assertions), warn(missing_docs))]
19#![cfg_attr(not(debug_assertions), deny(broken_intra_doc_links))]
20#![cfg_attr(not(debug_assertions), deny(invalid_codeblock_attributes))]
21#![cfg_attr(not(debug_assertions), doc(test(attr(deny(warnings)))))]
22#![cfg_attr(not(debug_assertions), doc(test(attr(allow(dead_code)))))]
23#![cfg_attr(not(debug_assertions), doc(test(attr(allow(unused_variables)))))]
24
25mod guards;
26mod instrumented_future;
27mod labels;
28mod percentile;
29
30pub use guards::{
31    DeferredAdd, DeferredAddWithLabels, DeferredCounter, GaugeGuard, GenericGaugeGuard,
32    GuardedGauge, IntGaugeGuard,
33};
34pub use instrumented_future::{InstrumentedFuture, IntoInstrumentedFuture};
35pub use labels::{
36    HistogramWithLabels, IntCounterWithLabels, IntGaugeWithLabels, LabelValues, Labels,
37};
38pub use percentile::{Observations, Sample, TimingBucket, Windowing};
39
40#[allow(missing_docs)]
41pub mod paste_crate {
42    pub use paste::*;
43}
44
45// See `label_enum!` below; the factoring into two macros is to accomodate parsing
46// multiple kinds of visibility annotations.
47#[macro_export]
48#[doc(hidden)]
49macro_rules! __label_enum_internal {
50    ($(#[$attr:meta])* ($($vis:tt)*) enum $N:ident { $($(#[$var_attr:meta])* $V:ident),* }) => {
51        $(#[$attr])* $($vis)* enum $N { $($(#[$var_attr])* $V),* }
52
53            $crate::paste_crate::paste! {
54                impl $N {
55                    /// The name of this enum variant, as a string slice.
56                    pub fn as_str(&self) -> &'static str {
57                        match self {
58                            $($N::$V => stringify!([<$V:snake>])),*
59                        }
60                    }
61
62                    /// A vector containing one instance of each of the enum's variants.
63                    pub fn all_variants() -> Vec<Self> {
64                        vec![$($N::$V),*]
65                    }
66                }
67            }
68    };
69}
70
71/// Declare an enum intended to be used as a Prometheus label.
72///
73/// This helper macro can only be used to define enums consisting of tags without values.
74/// Each tag corresponds to a possible Prometheus label value. The macro then generates
75/// two functions, `as_str` and `all_variants`, as described in the example below. Those
76/// funtions are intended to assist in implementing the [`Labels`] trait for a label struct
77/// that contains the enum, ensuring a consistent conversion to strings for label values,
78/// and that all possible variants are included when implementing `possible_label_values`.
79///
80/// [`Labels`]: trait.Labels.html
81///
82/// # Example
83///
84/// When using the macro, define exactly one `enum` inside, as you would normally:
85///
86/// ```ignore
87/// label_enum! {
88///     pub(crate) enum MyErrorLabel {
89///         IoError,
90///         TimeoutError,
91///         MemoryError,
92///     }
93/// }
94/// ```
95///
96/// The macro will declare the enum exactly as provided. But in addition, it will generate
97/// two functions:
98///
99/// ```ignore
100/// impl MyErrorLabel {
101///     /// The name of this enum variant, as a string slice.
102///     pub fn as_str(&self) -> &'static str { ... }
103///
104///     /// A vector containing one instance of each of the enum's variants.
105///     pub fn all_variants() -> Vec<Self> { ... }
106/// }
107/// ```
108#[macro_export(local_inner_macros)]
109macro_rules! label_enum {
110    ($(#[$attr:meta])* enum $N:ident { $($(#[$var_attr:meta])* $V:ident),* $(,)* }) => {
111        __label_enum_internal!($(#[$attr])* () enum $N { $($(#[$var_attr])* $V),* });
112    };
113    ($(#[$attr:meta])* pub enum $N:ident { $($(#[$var_attr:meta])* $V:ident),* $(,)* }) => {
114        __label_enum_internal!($(#[$attr])* (pub) enum $N { $($(#[$var_attr])* $V),* });
115    };
116    ($(#[$attr:meta])* pub ($($vis:tt)+) enum $N:ident { $($(#[$var_attr:meta])* $V:ident),* $(,)* }) => {
117        __label_enum_internal!($(#[$attr])* (pub ($($vis)+)) enum $N { $($(#[$var_attr])* $V),* });
118    };
119}