LCOV - code coverage report
Current view: top level - libs/metrics/src - lib.rs (source / functions) Coverage Total Hit
Test: 8ac049b474321fdc72ddcb56d7165153a1a900e8.info Lines: 100.0 % 56 56
Test Date: 2023-09-06 10:18:01 Functions: 100.0 % 10 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              : 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          517 : pub fn register_internal(c: Box<dyn Collector>) -> Result<()> {
      56          517 :     INTERNAL_REGISTRY.register(c)
      57          517 : }
      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          416 : pub fn gather() -> Vec<prometheus::proto::MetricFamily> {
      64          416 :     update_rusage_metrics();
      65          416 :     let mut mfs = prometheus::gather();
      66          416 :     let mut internal_mfs = INTERNAL_REGISTRY.gather();
      67          416 :     mfs.append(&mut internal_mfs);
      68          416 :     mfs
      69          416 : }
      70              : 
      71           69 : static DISK_IO_BYTES: Lazy<IntGaugeVec> = Lazy::new(|| {
      72           69 :     register_int_gauge_vec!(
      73           69 :         "libmetrics_disk_io_bytes_total",
      74           69 :         "Bytes written and read from disk, grouped by the operation (read|write)",
      75           69 :         &["io_operation"]
      76           69 :     )
      77           69 :     .expect("Failed to register disk i/o bytes int gauge vec")
      78           69 : });
      79              : 
      80           69 : static MAXRSS_KB: Lazy<IntGauge> = Lazy::new(|| {
      81           69 :     register_int_gauge!(
      82           69 :         "libmetrics_maxrss_kb",
      83           69 :         "Memory usage (Maximum Resident Set Size)"
      84           69 :     )
      85           69 :     .expect("Failed to register maxrss_kb int gauge")
      86           69 : });
      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         1478 : pub fn set_build_info_metric(revision: &str) {
      93         1478 :     let metric = register_int_gauge_vec!(
      94         1478 :         "libmetrics_build_info",
      95         1478 :         "Build/version information",
      96         1478 :         &["revision"]
      97         1478 :     )
      98         1478 :     .expect("Failed to register build info metric");
      99         1478 :     metric.with_label_values(&[revision]).set(1);
     100         1478 : }
     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          416 : fn update_rusage_metrics() {
     112          416 :     let rusage_stats = get_rusage_stats();
     113          416 : 
     114          416 :     const BYTES_IN_BLOCK: i64 = 512;
     115          416 :     DISK_IO_BYTES
     116          416 :         .with_label_values(&["read"])
     117          416 :         .set(rusage_stats.ru_inblock * BYTES_IN_BLOCK);
     118          416 :     DISK_IO_BYTES
     119          416 :         .with_label_values(&["write"])
     120          416 :         .set(rusage_stats.ru_oublock * BYTES_IN_BLOCK);
     121          416 :     MAXRSS_KB.set(rusage_stats.ru_maxrss);
     122          416 : }
     123              : 
     124          416 : fn get_rusage_stats() -> libc::rusage {
     125          416 :     let mut rusage = std::mem::MaybeUninit::uninit();
     126          416 : 
     127          416 :     // SAFETY: kernel will initialize the struct for us
     128          416 :     unsafe {
     129          416 :         let ret = libc::getrusage(libc::RUSAGE_SELF, rusage.as_mut_ptr());
     130          416 :         assert!(ret == 0, "getrusage failed: bad args");
     131          416 :         rusage.assume_init()
     132          416 :     }
     133          416 : }
        

Generated by: LCOV version 2.1-beta