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