diff --git a/Cargo.toml b/Cargo.toml index 7ff2107..62eebf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ description = "Rust library to retrieve system, kernel, and process metrics from [dependencies] env_logger = "0.11.3" -getset = "0.1.2" log = "0.4.21" serde = { version = "1.0.203", features = ["derive"] } serde_json = "1.0.117" diff --git a/FEATURES.md b/FEATURES.md index ad720c5..712f3ac 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1,4 +1,6 @@ Supported Features +* `/net/` + * ✅ `dev` * `/sys/class/` * ✅ `dmi/id` diff --git a/examples/net_dev.rs b/examples/net_dev.rs new file mode 100644 index 0000000..74c29da --- /dev/null +++ b/examples/net_dev.rs @@ -0,0 +1,16 @@ +use procsys::net_dev; + +fn main() { + env_logger::init(); + + let net_devices = net_dev::collect(); + + // print all network devices information in json output + match serde_json::to_string_pretty(&net_devices) { + Ok(output) => println!("{}", output), + Err(err) => { + log::error!("{}", err); + std::process::exit(1); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 0775349..a000901 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![doc = include_str!("../README.md")] pub mod error; +pub mod net_dev; pub mod sysfs; pub mod utils; diff --git a/src/net_dev.rs b/src/net_dev.rs new file mode 100644 index 0000000..9aecf39 --- /dev/null +++ b/src/net_dev.rs @@ -0,0 +1,134 @@ +use serde::Serialize; + +use crate::utils; + +/// NetDev contains a network device information parsed from /proc/net/dev +#[derive(Debug, Serialize, Clone)] +pub struct NetDev { + pub name: String, + pub rx_bytes: u64, + pub rx_packets: u64, + pub rx_errors: u64, + pub rx_dropped: u64, + pub rx_fifo: u64, + pub rx_frame: u64, + pub rx_compressed: u64, + pub rx_multicast: u64, + pub tx_bytes: u64, + pub tx_packets: u64, + pub tx_errors: u64, + pub tx_dropped: u64, + pub tx_fifo: u64, + pub tx_collisions: u64, + pub tx_carrier: u64, + pub tx_compressed: u64, +} + +impl NetDev { + fn new(name: String) -> Self { + NetDev { + name, + rx_bytes: 0, + rx_packets: 0, + rx_errors: 0, + rx_dropped: 0, + rx_fifo: 0, + rx_frame: 0, + rx_compressed: 0, + rx_multicast: 0, + tx_bytes: 0, + tx_packets: 0, + tx_errors: 0, + tx_dropped: 0, + tx_fifo: 0, + tx_collisions: 0, + tx_carrier: 0, + tx_compressed: 0, + } + } +} + +/// collects network device information +/// # Example +/// ``` +/// use procsys::net_dev; +/// +/// let net_devices = net_dev::collect(); +/// let json_output = serde_json::to_string_pretty(&net_devices).unwrap(); +/// println!("{}", json_output); +/// +/// ``` +pub fn collect() -> Vec { + let mut net_devices = Vec::new(); + + let mut line_index = 0; + + for line in utils::read_file_lines("/proc/net/dev") { + line_index += 1; + + if line_index <= 2 { + continue; + } + + let fields: Vec<&str> = line.trim().split(' ').filter(|s| !s.is_empty()).collect(); + + if fields.len() != 17 { + continue; + } + + let mut net_device = NetDev::new(fields[0].trim_matches(':').to_string()); + net_device.rx_bytes = fields[1].parse::().unwrap_or_default(); + net_device.rx_packets = fields[2].parse::().unwrap_or_default(); + net_device.rx_errors = fields[3].parse::().unwrap_or_default(); + net_device.rx_dropped = fields[4].parse::().unwrap_or_default(); + net_device.rx_fifo = fields[5].parse::().unwrap_or_default(); + net_device.rx_frame = fields[6].parse::().unwrap_or_default(); + net_device.rx_compressed = fields[7].parse::().unwrap_or_default(); + net_device.rx_multicast = fields[8].parse::().unwrap_or_default(); + net_device.tx_bytes = fields[9].parse::().unwrap_or_default(); + net_device.tx_packets = fields[10].parse::().unwrap_or_default(); + net_device.tx_errors = fields[11].parse::().unwrap_or_default(); + net_device.tx_dropped = fields[12].parse::().unwrap_or_default(); + net_device.tx_fifo = fields[13].parse::().unwrap_or_default(); + net_device.tx_collisions = fields[14].parse::().unwrap_or_default(); + net_device.tx_carrier = fields[15].parse::().unwrap_or_default(); + net_device.tx_compressed = fields[16].parse::().unwrap_or_default(); + + net_devices.push(net_device); + + line_index += 1; + } + + net_devices +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn net_devices() { + let ndevices = collect(); + assert!(!ndevices.is_empty()); + + for net_dev in ndevices { + assert!(!net_dev.name.is_empty()); + assert!(net_dev.rx_bytes.ge(&0)); + assert!(net_dev.rx_packets.ge(&0)); + assert!(net_dev.rx_errors.ge(&0)); + assert!(net_dev.rx_dropped.ge(&0)); + assert!(net_dev.rx_fifo.ge(&0)); + assert!(net_dev.rx_frame.ge(&0)); + assert!(net_dev.rx_compressed.ge(&0)); + assert!(net_dev.rx_multicast.ge(&0)); + assert!(net_dev.tx_bytes.ge(&0)); + assert!(net_dev.tx_packets.ge(&0)); + assert!(net_dev.tx_errors.ge(&0)); + assert!(net_dev.tx_dropped.ge(&0)); + assert!(net_dev.tx_fifo.ge(&0)); + assert!(net_dev.tx_collisions.ge(&0)); + assert!(net_dev.tx_carrier.ge(&0)); + assert!(net_dev.tx_compressed.ge(&0)); + } + } +} diff --git a/src/utils.rs b/src/utils.rs index 77a9c54..84359b0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,8 @@ -use std::{fs, path::Path}; +use std::{ + fs::{self, File}, + io::{BufRead, BufReader}, + path::{Path, PathBuf}, +}; use walkdir::WalkDir; @@ -72,3 +76,22 @@ pub fn list_dir_content( content } + +pub fn read_file_lines(filename: &str) -> Vec { + let mut result = Vec::new(); + + match File::open(filename) { + Ok(file) => { + let reader = BufReader::new(file); + for line_result in reader.lines() { + match line_result { + Ok(line) => result.push(line), + Err(err) => log::error!("{}", err), + } + } + } + Err(err) => log::error!("{}", MetricError::IOError(PathBuf::from(filename), err)), + } + + result +}