LCOV - differential code coverage report
Current view: top level - libs/metrics/src - lib.rs (source / functions) Coverage Total Hit UBC CBC
Current: cd44433dd675caa99df17a61b18949c8387e2242.info Lines: 80.2 % 96 77 19 77
Current Date: 2024-01-09 02:06:09 Functions: 57.1 % 28 16 12 16
Baseline: 66c52a629a0f4a503e193045e0df4c77139e344b.info
Baseline Date: 2024-01-08 15:34:46

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

Generated by: LCOV version 2.1-beta