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() })
 }