iroh_metrics/static_core.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
//! Metrics collection in a static, process-level global metrics collector.
//!
//! Enables and manages a global registry of metrics.
//! Divided up into modules, each module has its own metrics.
//!
//! - To increment a **counter**, use the [`crate::inc`] macro with a value.
//! - To increment a **counter** by 1, use the [`crate::inc_by`] macro.
//!
//! To expose the metrics, start the metrics service with `start_metrics_server()`.
//!
//! # Example:
//! ```rust
//! use std::sync::Arc;
//!
//! use iroh_metrics::{inc, inc_by, static_core::Core, Counter, MetricsGroup};
//!
//! #[derive(Debug, Default, MetricsGroup)]
//! #[metrics(name = "my_metrics")]
//! pub struct Metrics {
//! /// things_added tracks the number of things we have added
//! pub things_added: Counter,
//! }
//!
//! Core::init(|reg, metrics| {
//! let m = Arc::new(Metrics::default());
//! reg.register(m.clone());
//! metrics.insert(m);
//! });
//!
//! inc_by!(Metrics, things_added, 2);
//! inc!(Metrics, things_added);
//! ```
use std::sync::OnceLock;
use erased_set::ErasedSyncSet;
use crate::{Error, MetricsGroup, MetricsSource, NoMetricsSnafu, Registry};
#[cfg(not(feature = "metrics"))]
type Registry = ();
/// This struct can be used with the functions in [`crate::service`] to use them with
/// the global static [`Core`] defined in this module.
#[cfg(feature = "service")]
#[derive(Clone, Copy, Debug)]
pub struct GlobalRegistry;
impl MetricsSource for GlobalRegistry {
fn encode_openmetrics(&self, writer: &mut impl std::fmt::Write) -> Result<(), Error> {
let core = crate::static_core::Core::get().ok_or(NoMetricsSnafu.build())?;
core.registry.encode_openmetrics(writer)
}
}
static CORE: OnceLock<Core> = OnceLock::new();
/// Core is the base metrics struct.
///
/// It manages the mapping between the metrics name and the actual metrics.
/// It also carries a single prometheus registry to be used by all metrics.
#[derive(Debug, Default)]
pub struct Core {
#[cfg(feature = "metrics")]
registry: Registry,
metrics_map: ErasedSyncSet,
}
impl Core {
/// Must only be called once to init metrics.
///
/// Panics if called a second time.
pub fn init<F: FnOnce(&mut Registry, &mut ErasedSyncSet)>(f: F) {
Self::try_init(f).expect("must only be called once");
}
/// Trieds to init the metrics.
#[cfg_attr(not(feature = "metrics"), allow(clippy::let_unit_value))]
pub fn try_init<F: FnOnce(&mut Registry, &mut ErasedSyncSet)>(f: F) -> std::io::Result<()> {
let mut registry = Registry::default();
let mut metrics_map = ErasedSyncSet::new();
f(&mut registry, &mut metrics_map);
CORE.set(Core {
metrics_map,
#[cfg(feature = "metrics")]
registry,
})
.map_err(|_| std::io::Error::other("already set"))
}
/// Returns a reference to the core metrics.
pub fn get() -> Option<&'static Self> {
CORE.get()
}
/// Returns a reference to the prometheus registry.
#[cfg(feature = "metrics")]
pub fn registry(&self) -> &Registry {
&self.registry
}
/// Returns a reference to the mapped metrics instance.
pub fn get_collector<T: MetricsGroup>(&self) -> Option<&T> {
self.metrics_map.get::<T>()
}
/// Encodes the current metrics registry to a string in
/// the prometheus text exposition format.
#[cfg(feature = "metrics")]
pub fn encode_openmetrics(&self) -> String {
use crate::MetricsSource;
self.registry()
.encode_openmetrics_to_string()
.expect("encoding to string never fails")
}
}
/// Increments the given metric by 1.
#[macro_export]
macro_rules! inc {
($m:ty, $f:ident) => {
if let Some(m) = $crate::static_core::Core::get().and_then(|c| c.get_collector::<$m>()) {
m.$f.inc();
}
};
}
/// Increments the given metric by `n`.
#[macro_export]
macro_rules! inc_by {
($m:ty, $f:ident, $n:expr) => {
if let Some(m) = $crate::static_core::Core::get().and_then(|c| c.get_collector::<$m>()) {
m.$f.inc_by($n);
}
};
}
/// Sets the given metric to `n`.
#[macro_export]
macro_rules! set {
($m:ty, $f:ident, $n:expr) => {
<$m as $crate::static_core::Metric>::with_metric(|m| m.$f.set($n));
};
}
/// Decrements the given metric by 1.
#[macro_export]
macro_rules! dec {
($m:ty, $f:ident) => {
if let Some(m) = $crate::static_core::Core::get().and_then(|c| c.get_collector::<$m>()) {
m.$f.dec();
}
};
}
/// Decrements the given metric by `n`.
#[macro_export]
macro_rules! dec_by {
($m:ty, $f:ident, $n:expr) => {
if let Some(m) = $crate::static_core::Core::get().and_then(|c| c.get_collector::<$m>()) {
m.$f.dec_by($n);
}
};
}