LCOV - differential code coverage report
Current view: top level - libs/metrics/src - lib.rs (source / functions) Coverage Total Hit CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 100.0 % 56 56 56
Current Date: 2023-10-19 02:04:12 Functions: 100.0 % 10 10 10
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           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                 : use once_cell::sync::Lazy;
       6                 : use prometheus::core::{AtomicU64, Collector, GenericGauge, GenericGaugeVec};
       7                 : pub use prometheus::opts;
       8                 : pub use prometheus::register;
       9                 : pub use prometheus::Error;
      10                 : pub use prometheus::{core, default_registry, proto};
      11                 : pub use prometheus::{exponential_buckets, linear_buckets};
      12                 : pub use prometheus::{register_counter_vec, Counter, CounterVec};
      13                 : pub use prometheus::{register_gauge, Gauge};
      14                 : pub use prometheus::{register_gauge_vec, GaugeVec};
      15                 : pub use prometheus::{register_histogram, Histogram};
      16                 : pub use prometheus::{register_histogram_vec, HistogramVec};
      17                 : pub use prometheus::{register_int_counter, IntCounter};
      18                 : pub use prometheus::{register_int_counter_vec, IntCounterVec};
      19                 : pub use prometheus::{register_int_gauge, IntGauge};
      20                 : pub use prometheus::{register_int_gauge_vec, IntGaugeVec};
      21                 : pub use prometheus::{Encoder, TextEncoder};
      22                 : use prometheus::{Registry, Result};
      23                 : 
      24                 : pub mod launch_timestamp;
      25                 : mod wrappers;
      26                 : pub use wrappers::{CountedReader, CountedWriter};
      27                 : pub mod metric_vec_duration;
      28                 : 
      29                 : pub type UIntGauge = GenericGauge<AtomicU64>;
      30                 : pub type UIntGaugeVec = GenericGaugeVec<AtomicU64>;
      31                 : 
      32                 : #[macro_export]
      33                 : macro_rules! register_uint_gauge_vec {
      34                 :     ($NAME:expr, $HELP:expr, $LABELS_NAMES:expr $(,)?) => {{
      35                 :         let gauge_vec = UIntGaugeVec::new($crate::opts!($NAME, $HELP), $LABELS_NAMES).unwrap();
      36                 :         $crate::register(Box::new(gauge_vec.clone())).map(|_| gauge_vec)
      37                 :     }};
      38                 : }
      39                 : 
      40                 : #[macro_export]
      41                 : macro_rules! register_uint_gauge {
      42                 :     ($NAME:expr, $HELP:expr $(,)?) => {{
      43                 :         let gauge = $crate::UIntGauge::new($NAME, $HELP).unwrap();
      44                 :         $crate::register(Box::new(gauge.clone())).map(|_| gauge)
      45                 :     }};
      46                 : }
      47                 : 
      48                 : /// Special internal registry, to collect metrics independently from the default registry.
      49                 : /// Was introduced to fix deadlock with lazy registration of metrics in the default registry.
      50                 : static INTERNAL_REGISTRY: Lazy<Registry> = Lazy::new(Registry::new);
      51                 : 
      52                 : /// Register a collector in the internal registry. MUST be called before the first call to `gather()`.
      53                 : /// Otherwise, we can have a deadlock in the `gather()` call, trying to register a new collector
      54                 : /// while holding the lock.
      55 CBC         500 : pub fn register_internal(c: Box<dyn Collector>) -> Result<()> {
      56             500 :     INTERNAL_REGISTRY.register(c)
      57             500 : }
      58                 : 
      59                 : /// Gathers all Prometheus metrics and records the I/O stats just before that.
      60                 : ///
      61                 : /// Metrics gathering is a relatively simple and standalone operation, so
      62                 : /// it might be fine to do it this way to keep things simple.
      63             565 : pub fn gather() -> Vec<prometheus::proto::MetricFamily> {
      64             565 :     update_rusage_metrics();
      65             565 :     let mut mfs = prometheus::gather();
      66             565 :     let mut internal_mfs = INTERNAL_REGISTRY.gather();
      67             565 :     mfs.append(&mut internal_mfs);
      68             565 :     mfs
      69             565 : }
      70                 : 
      71              81 : static DISK_IO_BYTES: Lazy<IntGaugeVec> = Lazy::new(|| {
      72              81 :     register_int_gauge_vec!(
      73              81 :         "libmetrics_disk_io_bytes_total",
      74              81 :         "Bytes written and read from disk, grouped by the operation (read|write)",
      75              81 :         &["io_operation"]
      76              81 :     )
      77              81 :     .expect("Failed to register disk i/o bytes int gauge vec")
      78              81 : });
      79                 : 
      80              81 : static MAXRSS_KB: Lazy<IntGauge> = Lazy::new(|| {
      81              81 :     register_int_gauge!(
      82              81 :         "libmetrics_maxrss_kb",
      83              81 :         "Memory usage (Maximum Resident Set Size)"
      84              81 :     )
      85              81 :     .expect("Failed to register maxrss_kb int gauge")
      86              81 : });
      87                 : 
      88                 : pub const DISK_WRITE_SECONDS_BUCKETS: &[f64] = &[
      89                 :     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,
      90                 : ];
      91                 : 
      92            1428 : pub fn set_build_info_metric(revision: &str) {
      93            1428 :     let metric = register_int_gauge_vec!(
      94            1428 :         "libmetrics_build_info",
      95            1428 :         "Build/version information",
      96            1428 :         &["revision"]
      97            1428 :     )
      98            1428 :     .expect("Failed to register build info metric");
      99            1428 :     metric.with_label_values(&[revision]).set(1);
     100            1428 : }
     101                 : 
     102                 : // Records I/O stats in a "cross-platform" way.
     103                 : // Compiles both on macOS and Linux, but current macOS implementation always returns 0 as values for I/O stats.
     104                 : // An alternative is to read procfs (`/proc/[pid]/io`) which does not work under macOS at all, hence abandoned.
     105                 : //
     106                 : // Uses https://www.freebsd.org/cgi/man.cgi?query=getrusage to retrieve the number of block operations
     107                 : // performed by the process.
     108                 : // We know the size of the block, so we can determine the I/O bytes out of it.
     109                 : // The value might be not 100% exact, but should be fine for Prometheus metrics in this case.
     110                 : #[allow(clippy::unnecessary_cast)]
     111             565 : fn update_rusage_metrics() {
     112             565 :     let rusage_stats = get_rusage_stats();
     113             565 : 
     114             565 :     const BYTES_IN_BLOCK: i64 = 512;
     115             565 :     DISK_IO_BYTES
     116             565 :         .with_label_values(&["read"])
     117             565 :         .set(rusage_stats.ru_inblock * BYTES_IN_BLOCK);
     118             565 :     DISK_IO_BYTES
     119             565 :         .with_label_values(&["write"])
     120             565 :         .set(rusage_stats.ru_oublock * BYTES_IN_BLOCK);
     121             565 :     MAXRSS_KB.set(rusage_stats.ru_maxrss);
     122             565 : }
     123                 : 
     124             565 : fn get_rusage_stats() -> libc::rusage {
     125             565 :     let mut rusage = std::mem::MaybeUninit::uninit();
     126             565 : 
     127             565 :     // SAFETY: kernel will initialize the struct for us
     128             565 :     unsafe {
     129             565 :         let ret = libc::getrusage(libc::RUSAGE_SELF, rusage.as_mut_ptr());
     130             565 :         assert!(ret == 0, "getrusage failed: bad args");
     131             565 :         rusage.assume_init()
     132             565 :     }
     133             565 : }
        

Generated by: LCOV version 2.1-beta