Line data Source code
1 : //! process metrics that the [`::prometheus`] crate doesn't provide.
2 :
3 : // This module has heavy inspiration from the prometheus crate's `process_collector.rs`.
4 :
5 : use once_cell::sync::Lazy;
6 : use prometheus::Gauge;
7 :
8 : use crate::UIntGauge;
9 :
10 : pub struct Collector {
11 : descs: Vec<prometheus::core::Desc>,
12 : vmlck: crate::UIntGauge,
13 : cpu_seconds_highres: Gauge,
14 : }
15 :
16 : const NMETRICS: usize = 2;
17 :
18 0 : static CLK_TCK_F64: Lazy<f64> = Lazy::new(|| {
19 : // SAFETY: libc::sysconf is safe, it merely returns a value.
20 0 : let long = unsafe { libc::sysconf(libc::_SC_CLK_TCK) };
21 0 : if long == -1 {
22 0 : panic!("sysconf(_SC_CLK_TCK) failed");
23 0 : }
24 0 : let convertible_to_f64: i32 =
25 0 : i32::try_from(long).expect("sysconf(_SC_CLK_TCK) is larger than i32");
26 0 : convertible_to_f64 as f64
27 0 : });
28 :
29 : impl prometheus::core::Collector for Collector {
30 0 : fn desc(&self) -> Vec<&prometheus::core::Desc> {
31 0 : self.descs.iter().collect()
32 0 : }
33 :
34 0 : fn collect(&self) -> Vec<prometheus::proto::MetricFamily> {
35 0 : let Ok(myself) = procfs::process::Process::myself() else {
36 0 : return vec![];
37 : };
38 0 : let mut mfs = Vec::with_capacity(NMETRICS);
39 0 : if let Ok(status) = myself.status() {
40 0 : if let Some(vmlck) = status.vmlck {
41 0 : self.vmlck.set(vmlck);
42 0 : mfs.extend(self.vmlck.collect())
43 0 : }
44 0 : }
45 0 : if let Ok(stat) = myself.stat() {
46 0 : let cpu_seconds = stat.utime + stat.stime;
47 0 : self.cpu_seconds_highres
48 0 : .set(cpu_seconds as f64 / *CLK_TCK_F64);
49 0 : mfs.extend(self.cpu_seconds_highres.collect());
50 0 : }
51 0 : mfs
52 0 : }
53 : }
54 :
55 : impl Collector {
56 0 : pub fn new() -> Self {
57 0 : let mut descs = Vec::new();
58 :
59 0 : let vmlck =
60 0 : UIntGauge::new("libmetrics_process_status_vmlck", "/proc/self/status vmlck").unwrap();
61 0 : descs.extend(
62 0 : prometheus::core::Collector::desc(&vmlck)
63 0 : .into_iter()
64 0 : .cloned(),
65 : );
66 :
67 0 : let cpu_seconds_highres = Gauge::new(
68 : "libmetrics_process_cpu_seconds_highres",
69 : "Total user and system CPU time spent in seconds.\
70 : Sub-second resolution, hence better than `process_cpu_seconds_total`.",
71 : )
72 0 : .unwrap();
73 0 : descs.extend(
74 0 : prometheus::core::Collector::desc(&cpu_seconds_highres)
75 0 : .into_iter()
76 0 : .cloned(),
77 : );
78 :
79 0 : Self {
80 0 : descs,
81 0 : vmlck,
82 0 : cpu_seconds_highres,
83 0 : }
84 0 : }
85 : }
86 :
87 : impl Default for Collector {
88 0 : fn default() -> Self {
89 0 : Self::new()
90 0 : }
91 : }
|