LCOV - code coverage report
Current view: top level - libs/metrics/src - lib.rs (source / functions) Coverage Total Hit
Test: 36bb8dd7c7efcb53483d1a7d9f7cb33e8406dcf0.info Lines: 34.9 % 106 37
Test Date: 2024-04-08 10:22:05 Functions: 29.4 % 34 10

            Line data    Source code
       1              : //! We re-export those from prometheus crate to
       2              : //! make sure that we use the same dep version everywhere.
       3              : //! Otherwise, we might not see all metrics registered via
       4              : //! a default registry.
       5              : #![deny(clippy::undocumented_unsafe_blocks)]
       6              : 
       7              : use once_cell::sync::Lazy;
       8              : use prometheus::core::{
       9              :     Atomic, AtomicU64, Collector, GenericCounter, GenericCounterVec, GenericGauge, GenericGaugeVec,
      10              : };
      11              : pub use prometheus::opts;
      12              : pub use prometheus::register;
      13              : pub use prometheus::Error;
      14              : pub use prometheus::{core, default_registry, proto};
      15              : pub use prometheus::{exponential_buckets, linear_buckets};
      16              : pub use prometheus::{register_counter_vec, Counter, CounterVec};
      17              : pub use prometheus::{register_gauge, Gauge};
      18              : pub use prometheus::{register_gauge_vec, GaugeVec};
      19              : pub use prometheus::{register_histogram, Histogram};
      20              : pub use prometheus::{register_histogram_vec, HistogramVec};
      21              : pub use prometheus::{register_int_counter, IntCounter};
      22              : pub use prometheus::{register_int_counter_vec, IntCounterVec};
      23              : pub use prometheus::{register_int_gauge, IntGauge};
      24              : pub use prometheus::{register_int_gauge_vec, IntGaugeVec};
      25              : pub use prometheus::{Encoder, TextEncoder};
      26              : use prometheus::{Registry, Result};
      27              : 
      28              : pub mod launch_timestamp;
      29              : mod wrappers;
      30              : pub use wrappers::{CountedReader, CountedWriter};
      31              : mod hll;
      32              : pub use hll::{HyperLogLog, HyperLogLogVec};
      33              : #[cfg(target_os = "linux")]
      34              : pub mod more_process_metrics;
      35              : 
      36              : pub type UIntGauge = GenericGauge<AtomicU64>;
      37              : pub type UIntGaugeVec = GenericGaugeVec<AtomicU64>;
      38              : 
      39              : #[macro_export]
      40              : macro_rules! register_uint_gauge_vec {
      41              :     ($NAME:expr, $HELP:expr, $LABELS_NAMES:expr $(,)?) => {{
      42              :         let gauge_vec = UIntGaugeVec::new($crate::opts!($NAME, $HELP), $LABELS_NAMES).unwrap();
      43              :         $crate::register(Box::new(gauge_vec.clone())).map(|_| gauge_vec)
      44              :     }};
      45              : }
      46              : 
      47              : #[macro_export]
      48              : macro_rules! register_uint_gauge {
      49              :     ($NAME:expr, $HELP:expr $(,)?) => {{
      50              :         let gauge = $crate::UIntGauge::new($NAME, $HELP).unwrap();
      51              :         $crate::register(Box::new(gauge.clone())).map(|_| gauge)
      52              :     }};
      53              : }
      54              : 
      55              : /// Special internal registry, to collect metrics independently from the default registry.
      56              : /// Was introduced to fix deadlock with lazy registration of metrics in the default registry.
      57              : static INTERNAL_REGISTRY: Lazy<Registry> = Lazy::new(Registry::new);
      58              : 
      59              : /// Register a collector in the internal registry. MUST be called before the first call to `gather()`.
      60              : /// Otherwise, we can have a deadlock in the `gather()` call, trying to register a new collector
      61              : /// while holding the lock.
      62            0 : pub fn register_internal(c: Box<dyn Collector>) -> Result<()> {
      63            0 :     INTERNAL_REGISTRY.register(c)
      64            0 : }
      65              : 
      66              : /// Gathers all Prometheus metrics and records the I/O stats just before that.
      67              : ///
      68              : /// Metrics gathering is a relatively simple and standalone operation, so
      69              : /// it might be fine to do it this way to keep things simple.
      70            0 : pub fn gather() -> Vec<prometheus::proto::MetricFamily> {
      71            0 :     update_rusage_metrics();
      72            0 :     let mut mfs = prometheus::gather();
      73            0 :     let mut internal_mfs = INTERNAL_REGISTRY.gather();
      74            0 :     mfs.append(&mut internal_mfs);
      75            0 :     mfs
      76            0 : }
      77              : 
      78            0 : static DISK_IO_BYTES: Lazy<IntGaugeVec> = Lazy::new(|| {
      79            0 :     register_int_gauge_vec!(
      80            0 :         "libmetrics_disk_io_bytes_total",
      81            0 :         "Bytes written and read from disk, grouped by the operation (read|write)",
      82            0 :         &["io_operation"]
      83            0 :     )
      84            0 :     .expect("Failed to register disk i/o bytes int gauge vec")
      85            0 : });
      86              : 
      87            0 : static MAXRSS_KB: Lazy<IntGauge> = Lazy::new(|| {
      88            0 :     register_int_gauge!(
      89            0 :         "libmetrics_maxrss_kb",
      90            0 :         "Memory usage (Maximum Resident Set Size)"
      91            0 :     )
      92            0 :     .expect("Failed to register maxrss_kb int gauge")
      93            0 : });
      94              : 
      95              : pub const DISK_WRITE_SECONDS_BUCKETS: &[f64] = &[
      96              :     0.000_050, 0.000_100, 0.000_500, 0.001, 0.003, 0.005, 0.01, 0.05, 0.1, 0.3, 0.5,
      97              : ];
      98              : 
      99            0 : pub fn set_build_info_metric(revision: &str, build_tag: &str) {
     100            0 :     let metric = register_int_gauge_vec!(
     101            0 :         "libmetrics_build_info",
     102            0 :         "Build/version information",
     103            0 :         &["revision", "build_tag"]
     104            0 :     )
     105            0 :     .expect("Failed to register build info metric");
     106            0 :     metric.with_label_values(&[revision, build_tag]).set(1);
     107            0 : }
     108              : 
     109              : // Records I/O stats in a "cross-platform" way.
     110              : // Compiles both on macOS and Linux, but current macOS implementation always returns 0 as values for I/O stats.
     111              : // An alternative is to read procfs (`/proc/[pid]/io`) which does not work under macOS at all, hence abandoned.
     112              : //
     113              : // Uses https://www.freebsd.org/cgi/man.cgi?query=getrusage to retrieve the number of block operations
     114              : // performed by the process.
     115              : // We know the size of the block, so we can determine the I/O bytes out of it.
     116              : // The value might be not 100% exact, but should be fine for Prometheus metrics in this case.
     117            0 : fn update_rusage_metrics() {
     118            0 :     let rusage_stats = get_rusage_stats();
     119            0 : 
     120            0 :     const BYTES_IN_BLOCK: i64 = 512;
     121            0 :     DISK_IO_BYTES
     122            0 :         .with_label_values(&["read"])
     123            0 :         .set(rusage_stats.ru_inblock * BYTES_IN_BLOCK);
     124            0 :     DISK_IO_BYTES
     125            0 :         .with_label_values(&["write"])
     126            0 :         .set(rusage_stats.ru_oublock * BYTES_IN_BLOCK);
     127            0 :     MAXRSS_KB.set(rusage_stats.ru_maxrss);
     128            0 : }
     129              : 
     130            0 : fn get_rusage_stats() -> libc::rusage {
     131            0 :     let mut rusage = std::mem::MaybeUninit::uninit();
     132            0 : 
     133            0 :     // SAFETY: kernel will initialize the struct for us
     134            0 :     unsafe {
     135            0 :         let ret = libc::getrusage(libc::RUSAGE_SELF, rusage.as_mut_ptr());
     136            0 :         assert!(ret == 0, "getrusage failed: bad args");
     137            0 :         rusage.assume_init()
     138            0 :     }
     139            0 : }
     140              : 
     141              : /// Create an [`IntCounterPairVec`] and registers to default registry.
     142              : #[macro_export(local_inner_macros)]
     143              : macro_rules! register_int_counter_pair_vec {
     144              :     ($NAME1:expr, $HELP1:expr, $NAME2:expr, $HELP2:expr, $LABELS_NAMES:expr $(,)?) => {{
     145              :         match (
     146              :             $crate::register_int_counter_vec!($NAME1, $HELP1, $LABELS_NAMES),
     147              :             $crate::register_int_counter_vec!($NAME2, $HELP2, $LABELS_NAMES),
     148              :         ) {
     149              :             (Ok(inc), Ok(dec)) => Ok($crate::IntCounterPairVec::new(inc, dec)),
     150              :             (Err(e), _) | (_, Err(e)) => Err(e),
     151              :         }
     152              :     }};
     153              : }
     154              : /// Create an [`IntCounterPair`] and registers to default registry.
     155              : #[macro_export(local_inner_macros)]
     156              : macro_rules! register_int_counter_pair {
     157              :     ($NAME1:expr, $HELP1:expr, $NAME2:expr, $HELP2:expr $(,)?) => {{
     158              :         match (
     159              :             $crate::register_int_counter!($NAME1, $HELP1),
     160              :             $crate::register_int_counter!($NAME2, $HELP2),
     161              :         ) {
     162              :             (Ok(inc), Ok(dec)) => Ok($crate::IntCounterPair::new(inc, dec)),
     163              :             (Err(e), _) | (_, Err(e)) => Err(e),
     164              :         }
     165              :     }};
     166              : }
     167              : 
     168              : /// A Pair of [`GenericCounterVec`]s. Like an [`GenericGaugeVec`] but will always observe changes
     169              : pub struct GenericCounterPairVec<P: Atomic> {
     170              :     inc: GenericCounterVec<P>,
     171              :     dec: GenericCounterVec<P>,
     172              : }
     173              : 
     174              : /// A Pair of [`GenericCounter`]s. Like an [`GenericGauge`] but will always observe changes
     175              : pub struct GenericCounterPair<P: Atomic> {
     176              :     inc: GenericCounter<P>,
     177              :     dec: GenericCounter<P>,
     178              : }
     179              : 
     180              : impl<P: Atomic> GenericCounterPairVec<P> {
     181          106 :     pub fn new(inc: GenericCounterVec<P>, dec: GenericCounterVec<P>) -> Self {
     182          106 :         Self { inc, dec }
     183          106 :     }
     184              : 
     185              :     /// `get_metric_with_label_values` returns the [`GenericCounterPair<P>`] for the given slice
     186              :     /// of label values (same order as the VariableLabels in Desc). If that combination of
     187              :     /// label values is accessed for the first time, a new [`GenericCounterPair<P>`] is created.
     188              :     ///
     189              :     /// An error is returned if the number of label values is not the same as the
     190              :     /// number of VariableLabels in Desc.
     191         1052 :     pub fn get_metric_with_label_values(&self, vals: &[&str]) -> Result<GenericCounterPair<P>> {
     192         1052 :         Ok(GenericCounterPair {
     193         1052 :             inc: self.inc.get_metric_with_label_values(vals)?,
     194         1052 :             dec: self.dec.get_metric_with_label_values(vals)?,
     195              :         })
     196         1052 :     }
     197              : 
     198              :     /// `with_label_values` works as `get_metric_with_label_values`, but panics if an error
     199              :     /// occurs.
     200          510 :     pub fn with_label_values(&self, vals: &[&str]) -> GenericCounterPair<P> {
     201          510 :         self.get_metric_with_label_values(vals).unwrap()
     202          510 :     }
     203              : 
     204           22 :     pub fn remove_label_values(&self, res: &mut [Result<()>; 2], vals: &[&str]) {
     205           22 :         res[0] = self.inc.remove_label_values(vals);
     206           22 :         res[1] = self.dec.remove_label_values(vals);
     207           22 :     }
     208              : }
     209              : 
     210              : impl<P: Atomic> GenericCounterPair<P> {
     211            2 :     pub fn new(inc: GenericCounter<P>, dec: GenericCounter<P>) -> Self {
     212            2 :         Self { inc, dec }
     213            2 :     }
     214              : 
     215              :     /// Increment the gauge by 1, returning a guard that decrements by 1 on drop.
     216          514 :     pub fn guard(&self) -> GenericCounterPairGuard<P> {
     217          514 :         self.inc.inc();
     218          514 :         GenericCounterPairGuard(self.dec.clone())
     219          514 :     }
     220              : 
     221              :     /// Increment the gauge by n, returning a guard that decrements by n on drop.
     222            0 :     pub fn guard_by(&self, n: P::T) -> GenericCounterPairGuardBy<P> {
     223            0 :         self.inc.inc_by(n);
     224            0 :         GenericCounterPairGuardBy(self.dec.clone(), n)
     225            0 :     }
     226              : 
     227              :     /// Increase the gauge by 1.
     228              :     #[inline]
     229         2366 :     pub fn inc(&self) {
     230         2366 :         self.inc.inc();
     231         2366 :     }
     232              : 
     233              :     /// Decrease the gauge by 1.
     234              :     #[inline]
     235         2043 :     pub fn dec(&self) {
     236         2043 :         self.dec.inc();
     237         2043 :     }
     238              : 
     239              :     /// Add the given value to the gauge. (The value can be
     240              :     /// negative, resulting in a decrement of the gauge.)
     241              :     #[inline]
     242            0 :     pub fn inc_by(&self, v: P::T) {
     243            0 :         self.inc.inc_by(v);
     244            0 :     }
     245              : 
     246              :     /// Subtract the given value from the gauge. (The value can be
     247              :     /// negative, resulting in an increment of the gauge.)
     248              :     #[inline]
     249            0 :     pub fn dec_by(&self, v: P::T) {
     250            0 :         self.dec.inc_by(v);
     251            0 :     }
     252              : }
     253              : 
     254              : impl<P: Atomic> Clone for GenericCounterPair<P> {
     255         4383 :     fn clone(&self) -> Self {
     256         4383 :         Self {
     257         4383 :             inc: self.inc.clone(),
     258         4383 :             dec: self.dec.clone(),
     259         4383 :         }
     260         4383 :     }
     261              : }
     262              : 
     263              : /// Guard returned by [`GenericCounterPair::guard`]
     264              : pub struct GenericCounterPairGuard<P: Atomic>(GenericCounter<P>);
     265              : 
     266              : impl<P: Atomic> Drop for GenericCounterPairGuard<P> {
     267          514 :     fn drop(&mut self) {
     268          514 :         self.0.inc();
     269          514 :     }
     270              : }
     271              : /// Guard returned by [`GenericCounterPair::guard_by`]
     272              : pub struct GenericCounterPairGuardBy<P: Atomic>(GenericCounter<P>, P::T);
     273              : 
     274              : impl<P: Atomic> Drop for GenericCounterPairGuardBy<P> {
     275            0 :     fn drop(&mut self) {
     276            0 :         self.0.inc_by(self.1);
     277            0 :     }
     278              : }
     279              : 
     280              : /// A Pair of [`IntCounterVec`]s. Like an [`IntGaugeVec`] but will always observe changes
     281              : pub type IntCounterPairVec = GenericCounterPairVec<AtomicU64>;
     282              : 
     283              : /// A Pair of [`IntCounter`]s. Like an [`IntGauge`] but will always observe changes
     284              : pub type IntCounterPair = GenericCounterPair<AtomicU64>;
     285              : 
     286              : /// A guard for [`IntCounterPair`] that will decrement the gauge on drop
     287              : pub type IntCounterPairGuard = GenericCounterPairGuard<AtomicU64>;
        

Generated by: LCOV version 2.1-beta