metrics_process/
lib.rs

1#![doc = include_str!("../README.md")]
2pub mod collector;
3
4#[cfg(feature = "metrics-rs")]
5use std::sync::Arc;
6
7#[cfg(feature = "metrics-rs")]
8use metrics::{describe_gauge, gauge, Unit};
9
10#[cfg(all(
11    feature = "metrics-rs",
12    not(feature = "use-gauge-on-cpu-seconds-total")
13))]
14use metrics::{counter, describe_counter};
15
16/// Metrics names
17#[cfg(feature = "metrics-rs")]
18#[derive(Debug, PartialEq, Eq)]
19struct Metrics {
20    cpu_seconds_total: Arc<str>,
21    open_fds: Arc<str>,
22    max_fds: Arc<str>,
23    virtual_memory_bytes: Arc<str>,
24    virtual_memory_max_bytes: Arc<str>,
25    resident_memory_bytes: Arc<str>,
26    start_time_seconds: Arc<str>,
27    threads: Arc<str>,
28}
29
30#[cfg(feature = "metrics-rs")]
31impl Metrics {
32    // Create new Metrics, allocating prefixed strings for metrics names.
33    fn new(prefix: impl AsRef<str>) -> Self {
34        let prefix = prefix.as_ref();
35        Self {
36            cpu_seconds_total: format!("{prefix}process_cpu_seconds_total").into(),
37            open_fds: format!("{prefix}process_open_fds").into(),
38            max_fds: format!("{prefix}process_max_fds").into(),
39            virtual_memory_bytes: format!("{prefix}process_virtual_memory_bytes").into(),
40            virtual_memory_max_bytes: format!("{prefix}process_virtual_memory_max_bytes").into(),
41            resident_memory_bytes: format!("{prefix}process_resident_memory_bytes").into(),
42            start_time_seconds: format!("{prefix}process_start_time_seconds").into(),
43            threads: format!("{prefix}process_threads").into(),
44        }
45    }
46}
47
48#[cfg(feature = "metrics-rs")]
49impl Default for Metrics {
50    // Create new Metrics, without prefixing and thus allocating.
51    fn default() -> Self {
52        Self::new("")
53    }
54}
55
56/// Prometheus style process metrics collector for the [metrics] crate.
57///
58/// This is a collector which will directly export the metrics to the registered [metrics]
59/// collector.
60#[cfg(feature = "metrics-rs")]
61#[derive(Debug, Default, PartialEq, Eq, Clone)]
62pub struct Collector {
63    metrics: Arc<Metrics>,
64}
65
66#[cfg(feature = "metrics-rs")]
67impl Collector {
68    /// Add an prefix that is prepended to metric keys.
69    /// # Examples
70    ///
71    /// ```
72    /// # use metrics_process::Collector;
73    /// let collector = Collector::default().prefix("my_prefix_");
74    /// ```
75    ///
76    /// # Deprecated
77    ///
78    /// The new interface for creating a Collector should be utilized.
79    ///
80    /// ```
81    /// # use metrics_process::Collector;
82    /// let collector = Collector::new("my_prefix_");
83    /// ```
84    #[deprecated(since = "1.1.0", note = "Use `Collector::new(prefix)`.")]
85    pub fn prefix(self, prefix: impl Into<String>) -> Self {
86        let _ = self;
87        Self::new(prefix.into())
88    }
89
90    /// Create a new Collector instance with the provided prefix that is
91    /// prepended to metric keys.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// # use metrics_process::Collector;
97    /// let collector = Collector::default();
98    /// ```
99    pub fn new(prefix: impl AsRef<str>) -> Self {
100        Self {
101            metrics: Arc::new(Metrics::new(prefix)),
102        }
103    }
104
105    /// Describe available metrics through `describe_counter!` and `describe_gauge!` macro of `metrics` crate.
106    ///
107    /// # Example
108    ///
109    /// ```no_run
110    /// # use metrics_exporter_prometheus::PrometheusBuilder;
111    /// # use metrics_process::Collector;
112    /// # #[tokio::main]
113    /// # async fn main() {
114    /// // Recorder must be initialized prior to describe.
115    /// let builder = PrometheusBuilder::new();
116    /// builder.install().expect("failed to install recorder/exporter");
117    ///
118    /// let collector = Collector::default();
119    /// // Describe collector
120    /// collector.describe();
121    /// # }
122    /// ```
123    pub fn describe(&self) {
124        let metrics = self.metrics.as_ref();
125
126        #[cfg(not(feature = "use-gauge-on-cpu-seconds-total"))]
127        describe_counter!(
128            Arc::clone(&metrics.cpu_seconds_total),
129            Unit::Seconds,
130            "Total user and system CPU time spent in seconds."
131        );
132        #[cfg(feature = "use-gauge-on-cpu-seconds-total")]
133        describe_gauge!(
134            Arc::clone(&metrics.cpu_seconds_total),
135            Unit::Seconds,
136            "Total user and system CPU time spent in seconds."
137        );
138        describe_gauge!(
139            Arc::clone(&metrics.open_fds),
140            Unit::Count,
141            "Number of open file descriptors."
142        );
143        describe_gauge!(
144            Arc::clone(&metrics.max_fds),
145            Unit::Count,
146            "Maximum number of open file descriptors."
147        );
148        describe_gauge!(
149            Arc::clone(&metrics.virtual_memory_bytes),
150            Unit::Bytes,
151            "Virtual memory size in bytes."
152        );
153        #[cfg(not(target_os = "windows"))]
154        describe_gauge!(
155            Arc::clone(&metrics.virtual_memory_max_bytes),
156            Unit::Bytes,
157            "Maximum amount of virtual memory available in bytes."
158        );
159        describe_gauge!(
160            Arc::clone(&metrics.resident_memory_bytes),
161            Unit::Bytes,
162            "Resident memory size in bytes."
163        );
164        describe_gauge!(
165            Arc::clone(&metrics.start_time_seconds),
166            Unit::Seconds,
167            "Start time of the process since unix epoch in seconds."
168        );
169        #[cfg(not(target_os = "windows"))]
170        describe_gauge!(
171            Arc::clone(&metrics.threads),
172            Unit::Count,
173            "Number of OS threads in the process."
174        );
175    }
176
177    /// Collect metrics and record through `counter!` and `gauge!` macro of `metrics` crate.
178    ///
179    /// # Example
180    ///
181    /// ```no_run
182    /// # use metrics_exporter_prometheus::PrometheusBuilder;
183    /// # use metrics_process::Collector;
184    /// # #[tokio::main]
185    /// # async fn main() {
186    /// // Recorder must be initialized prior to describe.
187    /// let builder = PrometheusBuilder::new();
188    /// builder.install().expect("failed to install recorder/exporter");
189    ///
190    /// let collector = Collector::default();
191    /// collector.describe();
192    /// // Collect metrics
193    /// collector.collect();
194    /// # }
195    /// ```
196    pub fn collect(&self) {
197        let metrics = self.metrics.as_ref();
198        let mut m = collector::collect();
199        if let Some(v) = m.cpu_seconds_total.take() {
200            #[cfg(not(feature = "use-gauge-on-cpu-seconds-total"))]
201            counter!(Arc::clone(&metrics.cpu_seconds_total)).absolute(v as u64);
202            #[cfg(feature = "use-gauge-on-cpu-seconds-total")]
203            gauge!(Arc::clone(&metrics.cpu_seconds_total)).set(v);
204        }
205        if let Some(v) = m.open_fds.take() {
206            gauge!(Arc::clone(&metrics.open_fds)).set(v as f64);
207        }
208        if let Some(v) = m.max_fds.take() {
209            gauge!(Arc::clone(&metrics.max_fds)).set(v as f64);
210        }
211        if let Some(v) = m.virtual_memory_bytes.take() {
212            gauge!(Arc::clone(&metrics.virtual_memory_bytes)).set(v as f64);
213        }
214        #[cfg(not(target_os = "windows"))]
215        if let Some(v) = m.virtual_memory_max_bytes.take() {
216            gauge!(Arc::clone(&metrics.virtual_memory_max_bytes)).set(v as f64);
217        }
218        if let Some(v) = m.resident_memory_bytes.take() {
219            gauge!(Arc::clone(&metrics.resident_memory_bytes)).set(v as f64);
220        }
221        if let Some(v) = m.start_time_seconds.take() {
222            gauge!(Arc::clone(&metrics.start_time_seconds)).set(v as f64);
223        }
224        #[cfg(not(target_os = "windows"))]
225        if let Some(v) = m.threads.take() {
226            gauge!(Arc::clone(&metrics.threads)).set(v as f64);
227        }
228    }
229}