Mercurial > lbo > hg > myi3stat
changeset 26:fc3487a89d63
Use the easy way and make the Metrics objects mutable
so no state translation is needed
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Tue, 16 Feb 2016 20:52:14 +0100 |
parents | d3a29c57367a |
children | 2e623c2fb4f1 |
files | src/framework.rs src/main.rs src/metrics/load.rs src/metrics/net.rs src/metrics/time.rs |
diffstat | 5 files changed, 40 insertions(+), 78 deletions(-) [+] |
line wrap: on
line diff
--- a/src/framework.rs Mon Feb 15 10:29:16 2016 +0000 +++ b/src/framework.rs Tue Feb 16 20:52:14 2016 +0100 @@ -1,6 +1,5 @@ #![allow(dead_code)] -use std::collections::{BTreeMap, BTreeSet}; use std::thread::sleep; use std::time::Duration; @@ -64,38 +63,15 @@ } } -/// State that is stored in a MetricState between rendering cycles. -#[derive(Clone)] -pub enum State { - Empty, - S(String), - I(i64), - F(f64), - C(Color), - BTS(BTreeSet<String>), -} - /// State that is passed to and returned from every render cycle. pub struct MetricState { - /// Arbitrary state - state: BTreeMap<String, State>, - /// Unix epoch in seconds. This is updated by the framework. pub last_called: i64, } impl MetricState { pub fn new() -> MetricState { - MetricState { - state: BTreeMap::new(), - last_called: 0, - } - } - pub fn get(&self, k: String) -> State { - self.state.get(&k).unwrap_or(&State::Empty).clone() - } - pub fn set(&mut self, k: String, v: State) { - self.state.insert(k, v); + MetricState { last_called: 0 } } /// Returns timestamp in epoch milliseconds. pub fn now() -> i64 { @@ -107,9 +83,9 @@ pub trait Metric { /// Initializes a metric using the string supplied as parameter to the command line argument. - fn init(&self, _: &mut MetricState, _: Option<String>) {} + fn init(&mut self, _: &mut MetricState, _: Option<String>) {} /// Renders the metric. - fn render(&self, st: &mut MetricState) -> RenderResult; + fn render(&mut self, st: &mut MetricState) -> RenderResult; } /// A metric that is active in the current run and updated for every cycle.
--- a/src/main.rs Mon Feb 15 10:29:16 2016 +0000 +++ b/src/main.rs Tue Feb 16 20:52:14 2016 +0100 @@ -91,7 +91,7 @@ let mut metrics = Vec::new(); // Look for every defined metric if the user wants to have it displayed. - for (metric_name, metric) in self.metrics.into_iter() { + for (metric_name, mut metric) in self.metrics.into_iter() { if matches.opt_present(&metric_name) { let mut st = MetricState::new(); metric.init(&mut st, matches.opt_str(&metric_name));
--- a/src/metrics/load.rs Mon Feb 15 10:29:16 2016 +0000 +++ b/src/metrics/load.rs Tue Feb 16 20:52:14 2016 +0100 @@ -10,7 +10,7 @@ impl LoadAvg { fn read_load_avg() -> (String, Color) { - let loads = read_procfs_file(String::from("loadavg")) + let loads = read_procfs_file(String::from("/loadavg")) .unwrap_or(String::from("0.0 0.0 0.0 ")); let re = Regex::new(r"([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+).*").unwrap(); @@ -44,7 +44,7 @@ } impl Metric for LoadAvg { - fn render(&self, _: &mut MetricState) -> RenderResult { + fn render(&mut self, _: &mut MetricState) -> RenderResult { let (loads, color) = LoadAvg::read_load_avg(); RenderResult::new(loads, color) }
--- a/src/metrics/net.rs Mon Feb 15 10:29:16 2016 +0000 +++ b/src/metrics/net.rs Tue Feb 16 20:52:14 2016 +0100 @@ -5,20 +5,25 @@ extern crate regex; use self::regex::Regex; -use std::collections::BTreeSet; +use std::collections::BTreeMap; // Interface name, transmitted bytes, received bytes. Used for both rates and counters! type IFStat = (String, u64, u64); -struct NetInterfaceMetric; +struct NetInterfaceMetric { + oldstat: BTreeMap<String, IFStat>, +} impl NetInterfaceMetric { + fn new() -> NetInterfaceMetric { + NetInterfaceMetric { oldstat: BTreeMap::new() } + } /// Obtain current counters from /proc/net/dev - fn get_stats(ifs: BTreeSet<String>) -> Vec<IFStat> { + fn get_stats(ifs: &BTreeMap<String, IFStat>) -> Vec<IFStat> { let ifstats; let mut processed_stats = Vec::with_capacity(ifs.len()); - match get_procfs_file_lines(String::from("net/dev")) { + match get_procfs_file_lines(String::from("/net/dev")) { None => ifstats = Vec::new(), Some(st) => ifstats = st, } @@ -33,7 +38,7 @@ match re.captures(&line) { None => continue, Some(caps) => { - if ifs.contains(caps.at(1).unwrap()) { + if ifs.contains_key(caps.at(1).unwrap()) { processed_stats.push(( String::from(caps.at(1).unwrap()), u64::from_str_radix(caps.at(2).unwrap(), 10).unwrap(), @@ -75,64 +80,51 @@ acc }) } - - /// Parse a "{rx} {tx}" string into an IFStat tuple - fn str_to_ifstat(name: String, s: String) -> IFStat { - let re = Regex::new(r"^(\d+) (\d+)$").unwrap(); - - match re.captures(&s) { - None => (name, 0, 0), - Some(caps) => { - let rx = u64::from_str_radix(caps.at(1).unwrap(), 10).unwrap(); - let tx = u64::from_str_radix(caps.at(2).unwrap(), 10).unwrap(); - (name, rx, tx) - } - } - } } impl Metric for NetInterfaceMetric { - fn init(&self, st: &mut MetricState, initarg: Option<String>) { + fn init(&mut self, _: &mut MetricState, initarg: Option<String>) { match initarg { None => (), Some(s) => { - let wanted_ifs: BTreeSet<String> = commaseparated_to_vec(s).into_iter().collect(); - st.set(String::from("ifs"), State::BTS(wanted_ifs)); + let mut wanted_ifs = BTreeMap::new(); + for intf in commaseparated_to_vec(s) { + wanted_ifs.insert(intf.clone(), (intf, 0, 0)); + } + self.oldstat = wanted_ifs; } } } - fn render(&self, st: &mut MetricState) -> RenderResult { + fn render(&mut self, st: &mut MetricState) -> RenderResult { let interval = (MetricState::now() - st.last_called) as u64; - let interfaces; - match st.get(String::from("ifs")) { - State::BTS(ifs) => interfaces = ifs, - _ => return RenderResult::new(String::from("n/a"), Color::Red), + if self.oldstat.is_empty() { + return RenderResult::new(String::from("n/a"), Color::Red); } // Get current counters - let newstats = NetInterfaceMetric::get_stats(interfaces); + let newstats = NetInterfaceMetric::get_stats(&self.oldstat); let mut rates: Vec<IFStat> = Vec::new(); // this is the final output for (ifname, rx, tx) in newstats { // Obtain previous rx/tx counts from state let oldstat; - match st.get(ifname.clone()) { - State::S(o) => oldstat = NetInterfaceMetric::str_to_ifstat(ifname.clone(), o), + match self.oldstat.get(&ifname) { + Some(o) => oldstat = o.clone(), _ => oldstat = (ifname.clone(), rx, tx), } // calculate rate over last interval match oldstat { - (ifname, oldrx, oldtx) => { + (ref ifname, oldrx, oldtx) => { rates.push((ifname.clone(), 1000 * (rx - oldrx) / interval, 1000 * (tx - oldtx) / interval)); - // Store current counters in state - st.set(ifname.clone(), State::S(format!("{} {}", rx, tx))); } } + // Store current counters in state + self.oldstat.insert(ifname.clone(), (ifname, rx, tx)); } RenderResult::new(NetInterfaceMetric::format_stats(rates), Color::Green) @@ -140,5 +132,5 @@ } pub fn make_net_metric() -> Box<Metric> { - Box::new(NetInterfaceMetric) + Box::new(NetInterfaceMetric::new()) }
--- a/src/metrics/time.rs Mon Feb 15 10:29:16 2016 +0000 +++ b/src/metrics/time.rs Tue Feb 16 20:52:14 2016 +0100 @@ -5,30 +5,24 @@ extern crate chrono; use self::chrono::Local; -struct TimeMetric; +struct TimeMetric { + fmt: String, +} const DEFAULT_FMT: &'static str = "%a %b %d %H:%M:%S %Y (%Z)"; impl Metric for TimeMetric { - fn init(&self, st: &mut MetricState, arg: Option<String>) { - st.set(String::from("format"), - State::S(arg.unwrap_or(String::from(DEFAULT_FMT)))); + fn init(&mut self, _: &mut MetricState, arg: Option<String>) { + self.fmt = arg.unwrap_or(String::from(DEFAULT_FMT)); } - fn render(&self, st: &mut MetricState) -> RenderResult { - let fmt; - - match st.get(String::from("format")) { - State::S(f) => fmt = f, - _ => fmt = String::from(DEFAULT_FMT), - } - + fn render(&mut self, _: &mut MetricState) -> RenderResult { let t = Local::now(); - let tstr = format!("{}", t.format(&fmt)); + let tstr = format!("{}", t.format(&self.fmt)); RenderResult::new(tstr, Color::Default) } } pub fn clock_metric() -> Box<Metric> { - Box::new(TimeMetric) + Box::new(TimeMetric { fmt: String::new() }) }