kubert_prometheus_process/
lib.rs1#![deny(
34 rust_2018_idioms,
35 clippy::disallowed_methods,
36 unsafe_code,
37 missing_docs
38)]
39#![cfg_attr(docsrs, feature(doc_cfg))]
40
41use prometheus_client::{
42 collector::Collector,
43 encoding::{DescriptorEncoder, EncodeMetric},
44 metrics::{
45 counter::ConstCounter,
46 gauge::{self, ConstGauge, Gauge},
47 MetricType,
48 },
49 registry::{Registry, Unit},
50};
51use std::time::{Instant, SystemTime, UNIX_EPOCH};
52
53#[cfg(target_os = "linux")]
54mod linux;
55
56pub fn register(reg: &mut Registry) -> std::io::Result<()> {
59 let start_time = Instant::now();
60 let start_time_from_epoch = SystemTime::now()
61 .duration_since(UNIX_EPOCH)
62 .expect("process start time");
63
64 #[cfg(target_os = "linux")]
65 let system = linux::System::load()?;
66
67 reg.register_with_unit(
68 "start_time",
69 "Time that the process started (in seconds since the UNIX epoch)",
70 Unit::Seconds,
71 ConstGauge::new(start_time_from_epoch.as_secs_f64()),
72 );
73
74 let clock_time_ts = Gauge::<f64, ClockMetric>::default();
75 reg.register_with_unit(
76 "clock_time",
77 "Current system time for this process",
78 Unit::Seconds,
79 clock_time_ts,
80 );
81
82 reg.register_collector(Box::new(ProcessCollector {
83 start_time,
84 #[cfg(target_os = "linux")]
85 system,
86 }));
87
88 Ok(())
89}
90
91#[derive(Debug)]
92struct ProcessCollector {
93 start_time: Instant,
94 #[cfg(target_os = "linux")]
95 system: linux::System,
96}
97
98impl Collector for ProcessCollector {
99 fn encode(&self, mut encoder: DescriptorEncoder<'_>) -> std::fmt::Result {
100 let uptime = ConstCounter::new(
101 Instant::now()
102 .saturating_duration_since(self.start_time)
103 .as_secs_f64(),
104 );
105 let ue = encoder.encode_descriptor(
106 "uptime",
107 "Total time since the process started (in seconds)",
108 Some(&Unit::Seconds),
109 MetricType::Counter,
110 )?;
111 uptime.encode(ue)?;
112
113 #[cfg(target_os = "linux")]
114 self.system.encode(encoder)?;
115
116 Ok(())
117 }
118}
119
120#[derive(Copy, Clone, Debug, Default)]
122struct ClockMetric;
123
124impl gauge::Atomic<f64> for ClockMetric {
125 fn inc(&self) -> f64 {
126 self.get()
127 }
128
129 fn inc_by(&self, _v: f64) -> f64 {
130 self.get()
131 }
132
133 fn dec(&self) -> f64 {
134 self.get()
135 }
136
137 fn dec_by(&self, _v: f64) -> f64 {
138 self.get()
139 }
140
141 fn set(&self, _v: f64) -> f64 {
142 self.get()
143 }
144
145 fn get(&self) -> f64 {
146 match SystemTime::now().duration_since(UNIX_EPOCH) {
147 Ok(elapsed) => elapsed.as_secs_f64().floor(),
148 Err(e) => {
149 tracing::warn!(
150 "System time is before the UNIX epoch; reporting negative timestamp"
151 );
152 -e.duration().as_secs_f64().floor()
153 }
154 }
155 }
156}