Skip to main content

proc_status/
status.rs

1use {
2    crate::*,
3    std::{
4        fs::File,
5        io::Read,
6    },
7};
8
9/// A snapshot of the status of a process
10///
11/// It's stored in a string to ensure consistency
12/// and can be kept around and compared.
13pub struct ProcStatus {
14    content: String,
15}
16
17impl ProcStatus {
18
19    /// read the proc status info of the current process.
20    ///
21    /// It's the same than `ProcStatus::read(ProcRef::ProcSelf)`
22    pub fn read() -> Result<Self, ProcStatusError> {
23        Self::read_for(ProcRef::ProcSelf)
24    }
25
26    /// read the proc status info of a process.
27    pub fn read_for(proc_ref: ProcRef) -> Result<Self, ProcStatusError> {
28        let mut file = match proc_ref {
29            ProcRef::ProcSelf => File::open("/proc/self/status"),
30            ProcRef::ProcId(id) => File::open(format!("/proc/{}/status", id)),
31        }?;
32        let mut content = String::new();
33        file.read_to_string(&mut content)?;
34        Ok(Self { content })
35    }
36
37    /// return an iterator over all key:value entries
38    pub fn entries(&self) -> ProcEntries<'_> {
39        ProcEntries::from_content(&self.content)
40    }
41
42    /// find an entry by name
43    pub fn entry(&self, key: &str) -> Result<ProcEntry<'_>, ProcStatusError> {
44        for entry in self.entries() {
45            let entry = entry?;
46            if entry.key == key {
47                return Ok(entry);
48            }
49        }
50        Err(ProcStatusError::EntryNotFound(key.to_string()))
51    }
52
53    /// return the value of an entry found by key
54    ///
55    /// Example:
56    /// ```
57    /// println!(
58    ///     "current process name: {:?}",
59    ///     proc_status::ProcStatus::read().unwrap().value("Name").unwrap(),
60    /// );
61    /// ```
62    /// Be careful that the values written as "xxx kB" are in
63    /// KiB, not kB, and are written this way for compatibility.
64    pub fn value(&self, key: &str) -> Result<&str, ProcStatusError> {
65        self.entry(key).map(|e| e.value)
66    }
67
68    /// return the value of a memory related entry in KiB
69    #[allow(non_snake_case)]
70    pub fn value_KiB(&self, key: &str) -> Result<usize, ProcStatusError> {
71        self.entry(key).and_then(|e| e.in_KiB())
72    }
73
74    /// return the current and peak ram usage of the process
75    pub fn mem_usage(&self) -> Result<MemUsage, ProcStatusError> {
76        self.value_KiB("VmRSS")
77            .and_then(|current| {
78                self.value_KiB("VmPeak")
79                    .map(|peak| MemUsage {
80                        current: current * 1024, // proc/status data are in KiB
81                        peak: peak * 1024,
82                    })
83            })
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    #[test]
91    fn test_read() {
92        let ps = ProcStatus::read().unwrap();
93        let name = ps.value("Name").unwrap();
94        println!("name: {:?}", name);
95        println!("VM peak: {:?}", ps.value("VmPeak").unwrap());
96        println!("VM peak KiB: {:?}", ps.entry("VmPeak").unwrap().in_KiB().unwrap());
97        mem_usage().unwrap();
98    }
99}