diff --git a/README.md b/README.md index d6f54f6..92a6d35 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,45 @@ ## Paw Paw is a Rust library for monitoring and controlling child processes. It provides a simple API for spawning processes, reading their output, and getting their memory and CPU usage. ### Usage To use Paw, first create a new instance of the `Paw` struct. You can specify the command to run, the arguments to pass to the command, and the duration to monitor the process for. Once you have a `Paw` instance, you can call the `watch()` method to start monitoring the process. The `watch()` method takes a callback function as an argument. The callback function will be called periodically with the current state of the process. The `PawResult` struct contains the following information about the process: - `info`: Information about the process, such as its memory usage, CPU usage, and uptime. - `process`: Information about the process command, such as the command name and arguments. The `PawDone` struct contains the following information about the process: - `stdout`: The standard output of the process. - `code`: The exit code of the process. ### Example The following example shows how to use Paw to monitor a Node.js process: ```rust use paw::{Paw, PawResult}; let paw = Paw::new("node", &["tests/test.js"], 500); let callback = move |result: PawResult| { println!("{:?}", result); }; match paw.watch(callback) { Ok(result) => println!("{:?}", result), Err(error) => println!("{error}"), } ``` ### Running the tests To run the tests, simply run the following command: ``` cargo test ``` - -### Contributing - -If you would like to contribute to Paw, please feel free to open an issue or pull request on GitHub. diff --git a/src/lib.rs b/src/lib.rs index 0be3ea9..05656ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,116 +1,114 @@ use psutil::process::{MemoryInfo, Process}; use std::io::{self, Read}; use std::process::{Command, Stdio}; +use std::thread::{sleep, spawn}; use std::time::{Duration, Instant}; #[derive(Debug)] pub struct Paw { command: String, arguments: Vec, duration: Duration, } #[derive(Debug, Clone)] pub struct PawResult<'a> { pub info: PawInfo, pub process: PawProcess<'a>, } #[derive(Debug, Clone)] pub struct PawProcess<'a> { pub cmd: &'a String, pub args: &'a Vec, } #[derive(Debug, Clone)] pub struct PawInfo { - pub memory_usage: Option, - pub cpu_usage: f64, pub uptime: u128, + pub memory_usage: Option, + pub cpu_percent: Option, } #[derive(Debug, Clone)] pub struct PawDone { pub stdout: String, pub code: Option, } impl Paw { pub fn new>(command: &str, arguments: &[T], duration: u64) -> Paw { Paw { command: command.to_string(), arguments: arguments.iter().map(|s| s.as_ref().to_string()).collect(), duration: Duration::from_millis(duration), } } pub fn watch(&self, callback: F) -> Result> { let mut child = Command::new(&self.command).args(&self.arguments).stdout(Stdio::piped()).spawn()?; let done: PawDone; let pid = child.id(); let start_time = Instant::now(); let stdout_handle = child.stdout.take().unwrap(); - let stdout_thread = std::thread::spawn(move || { + let stdout_thread = spawn(move || { let mut buffer = String::new(); let mut reader = io::BufReader::new(stdout_handle); reader.read_to_string(&mut buffer).unwrap(); buffer }); loop { + let uptime = start_time.elapsed().as_millis(); let mut memory_usage: Option = None; - if let Ok(process) = Process::new(pid) { - if let Ok(info) = process.memory_info() { - memory_usage = Some(info); - } + let mut cpu_percent: Option = None; + + if let Ok(mut process) = Process::new(pid) { + memory_usage = process.memory_info().ok(); + cpu_percent = process.cpu_percent().ok(); } - let elapsed_time = start_time.elapsed().as_millis(); let result = PawResult { - info: PawInfo { - memory_usage, - cpu_usage: 0.0, - uptime: elapsed_time, - }, + info: PawInfo { memory_usage, cpu_percent, uptime }, process: PawProcess { cmd: &self.command, args: &self.arguments, }, }; callback(result); - std::thread::sleep(self.duration); + sleep(self.duration); if let Some(status) = child.try_wait()? { done = PawDone { stdout: stdout_thread.join().unwrap(), code: status.code(), }; break; } } Ok(done) } } #[cfg(test)] mod tests { use super::*; #[test] fn watch() { let paw = Paw::new("node", &["tests/test.js"], 500); let callback = move |result: PawResult| { println!("{:?}", result); }; match paw.watch(callback) { Ok(result) => println!("{:?}", result), Err(error) => println!("{error}"), } } }