From e20c0b30193bfba06cd880dd5b0e55f94e2705f8 Mon Sep 17 00:00:00 2001 From: Navid Yaghoobi Date: Sun, 18 Aug 2024 17:46:17 +1000 Subject: [PATCH] added /proc//cgroup Signed-off-by: Navid Yaghoobi --- FEATURES.md | 1 + src/lib.rs | 1 + src/process_cgroup.rs | 84 +++++++++++++++++++++++++++++++++++++++++ test_data/fixtures.ttar | 5 +++ 4 files changed, 91 insertions(+) create mode 100644 src/process_cgroup.rs diff --git a/FEATURES.md b/FEATURES.md index 18e2664..92ebe21 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1,5 +1,6 @@ Supported Features * ✅ `/proc/` + * cgroup * cmdline * comm * cwd diff --git a/src/lib.rs b/src/lib.rs index 6c07f18..fc3cbcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub mod meminfo; pub mod net_dev; pub mod net_protocols; pub mod process; +pub mod process_cgroup; pub mod process_io; pub mod process_limits; pub mod swaps; diff --git a/src/process_cgroup.rs b/src/process_cgroup.rs new file mode 100644 index 0000000..e5ef2f1 --- /dev/null +++ b/src/process_cgroup.rs @@ -0,0 +1,84 @@ +use serde::Serialize; + +use crate::{ + error::{CollectResult, MetricError}, + process::Process, + utils, +}; + +/// ProcessCgroup models one line from /proc/[pid]/cgroup +#[derive(Debug, Serialize, Clone, Default)] +pub struct ProcessCgroup { + pub hierarchy_id: usize, + pub controllers: Vec, + pub path: String, +} + +impl ProcessCgroup { + pub fn new() -> Self { + Default::default() + } +} + +impl Process { + /// cgroup reads from /proc//cgroup and returns cgroup information of the process + pub fn cgroup(&self) -> CollectResult> { + let mut proc_cgroups = Vec::new(); + let proc_cgroup_path_str = format!("{:?}", self.path()); + let proc_cgroup_file = format!("{}/cgroup", proc_cgroup_path_str.replace("\"", "")); + + for line in utils::read_file_lines(&proc_cgroup_file)? { + let item_fields: Vec<&str> = line.trim().split(':').collect(); + if item_fields.len() != 3 { + return Err(MetricError::InvalidFieldNumberError( + "process cgroup".to_string(), + item_fields.len(), + line, + )); + } + + let mut proc_cgroup = ProcessCgroup::new(); + proc_cgroup.path = item_fields[2].trim().to_string(); + + match item_fields[0].parse::() { + Ok(v) => proc_cgroup.hierarchy_id = v, + Err(e) => return Err(MetricError::ParseIntError(item_fields[0].to_string(), e)), + } + + if item_fields[1].trim() != "" { + proc_cgroup.controllers = item_fields[1] + .trim() + .split(",") + .map(|c| c.to_string()) + .collect::>() + } + + proc_cgroups.push(proc_cgroup); + } + + Ok(proc_cgroups) + } +} + +#[cfg(test)] +mod tests { + use std::path::Path; + + use crate::process::*; + + #[test] + fn proc_cgroup() { + let proc_path = Path::new("test_data/fixtures/proc"); + let sys_proc = collect_from(proc_path, 26231).expect("running proc 26231"); + let sys_proc_cgroup = sys_proc.cgroup().expect("running proc 26231 cgroup stat"); + + assert_eq!(sys_proc_cgroup.len(), 1); + assert_eq!(sys_proc_cgroup[0].hierarchy_id, 1); + assert_eq!(sys_proc_cgroup[0].controllers.len(), 0); + assert_eq!(sys_proc_cgroup[0].path, "/user.slice/user-1000.slice/user@1000.service/app.slice/app-org.gnome.Terminal.slice/vte-spawn-fd5b6c83-c316-470a-9732-4db75febce50.scope"); + + let sys_proc = collect_from(proc_path, 26232).expect("running proc 26232"); + let sys_proc_cgroup = sys_proc.cgroup(); + assert_eq!(sys_proc_cgroup.is_err(), true); + } +} diff --git a/test_data/fixtures.ttar b/test_data/fixtures.ttar index a7c6963..231ef48 100644 --- a/test_data/fixtures.ttar +++ b/test_data/fixtures.ttar @@ -8,6 +8,11 @@ Mode: 755 Directory: fixtures/proc/26231 Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/26231/cgroup +Lines: 1 +1::/user.slice/user-1000.slice/user@1000.service/app.slice/app-org.gnome.Terminal.slice/vte-spawn-fd5b6c83-c316-470a-9732-4db75febce50.scope +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/proc/26231/cmdline Lines: 1 vimNULLBYTEtest.goNULLBYTE+10NULLBYTEEOF