vector/sources/host_metrics/
process.rs

1use std::ffi::OsStr;
2
3use sysinfo::{ProcessRefreshKind, ProcessesToUpdate, UpdateKind};
4use vector_lib::configurable::configurable_component;
5#[cfg(target_os = "linux")]
6use vector_lib::metric_tags;
7
8use super::{FilterList, HostMetrics, default_all_processes, example_processes};
9
10/// Options for the process metrics collector.
11#[configurable_component]
12#[derive(Clone, Debug, Default)]
13pub struct ProcessConfig {
14    /// Lists of process name patterns to include or exclude.
15    #[serde(default = "default_all_processes")]
16    #[configurable(metadata(docs::examples = "example_processes()"))]
17    processes: FilterList,
18}
19
20const RUNTIME: &str = "process_runtime";
21const CPU_USAGE: &str = "process_cpu_usage";
22const MEMORY_USAGE: &str = "process_memory_usage";
23const MEMORY_VIRTUAL_USAGE: &str = "process_memory_virtual_usage";
24
25impl HostMetrics {
26    pub async fn process_metrics(&mut self, output: &mut super::MetricsBuffer) {
27        self.system.refresh_processes_specifics(
28            ProcessesToUpdate::All,
29            true,
30            ProcessRefreshKind::default()
31                .with_memory()
32                .with_cpu()
33                .with_cmd(UpdateKind::OnlyIfNotSet),
34        );
35        output.name = "process";
36        let sep = OsStr::new(" ");
37        for (pid, process) in self.system.processes().iter().filter(|&(_, proc)| {
38            self.config
39                .process
40                .processes
41                .contains_str(proc.name().to_str())
42        }) {
43            let tags = || {
44                metric_tags!(
45                "pid" => pid.as_u32().to_string(),
46                "name" => process.name().to_str().unwrap_or("unknown"),
47                "command" => process.cmd().join(sep).to_str().unwrap_or(""))
48            };
49            output.gauge(CPU_USAGE, process.cpu_usage().into(), tags());
50            output.gauge(MEMORY_USAGE, process.memory() as f64, tags());
51            output.gauge(
52                MEMORY_VIRTUAL_USAGE,
53                process.virtual_memory() as f64,
54                tags(),
55            );
56            output.counter(RUNTIME, process.run_time() as f64, tags());
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::super::{HostMetrics, HostMetricsConfig, MetricsBuffer};
64    use crate::sources::host_metrics::tests::count_tag;
65
66    #[tokio::test]
67    async fn generates_process_metrics() {
68        let mut buffer = MetricsBuffer::new(None);
69        HostMetrics::new(HostMetricsConfig::default())
70            .process_metrics(&mut buffer)
71            .await;
72        let metrics = buffer.metrics;
73        assert!(!metrics.is_empty());
74
75        // All metrics are named process_*
76        assert!(
77            !metrics
78                .iter()
79                .any(|metric| !metric.name().starts_with("process_"))
80        );
81
82        // They should all have the required tag
83        assert_eq!(count_tag(&metrics, "pid"), metrics.len());
84        assert_eq!(count_tag(&metrics, "name"), metrics.len());
85        assert_eq!(count_tag(&metrics, "command"), metrics.len());
86    }
87}