buffett-core 0.1.1

Core library for Bitconch:buffett
use influx_db_client as influxdb;
use buffett_metrics::metrics;
use std::env;
use std::sync::atomic::{AtomicUsize, Ordering};
use buffett_timing::timing;

const DEFAULT_METRICS_RATE: usize = 100;

pub struct Counter {
    pub name: &'static str,
    pub counts: AtomicUsize,
    pub times: AtomicUsize,
    pub lastlog: AtomicUsize,
    pub lograte: AtomicUsize,
}

macro_rules! create_counter {
    ($name:expr, $lograte:expr) => {
        Counter {
            name: $name,
            counts: AtomicUsize::new(0),
            times: AtomicUsize::new(0),
            lastlog: AtomicUsize::new(0),
            lograte: AtomicUsize::new($lograte),
        }
    };
}

macro_rules! inc_counter {
    ($name:expr, $count:expr) => {
        unsafe { $name.inc($count) };
    };
}

macro_rules! inc_new_counter_info {
    ($name:expr, $count:expr) => {{
        inc_new_counter!($name, $count, Level::Info, 0);
    }};
    ($name:expr, $count:expr, $lograte:expr) => {{
        inc_new_counter!($name, $count, Level::Info, $lograte);
    }};
}

macro_rules! inc_new_counter {
    ($name:expr, $count:expr, $level:expr, $lograte:expr) => {{
        if log_enabled!($level) {
            static mut INC_NEW_COUNTER: Counter = create_counter!($name, $lograte);
            inc_counter!(INC_NEW_COUNTER, $count);
        }
    }};
}

impl Counter {
    fn default_log_rate() -> usize {
        let v = env::var("BITCONCH_DASHBOARD_RATE")
            .map(|x| x.parse().unwrap_or(DEFAULT_METRICS_RATE))
            .unwrap_or(DEFAULT_METRICS_RATE);
        if v == 0 {
            DEFAULT_METRICS_RATE
        } else {
            v
        }
    }
    pub fn inc(&mut self, events: usize) {
        let counts = self.counts.fetch_add(events, Ordering::Relaxed);
        let times = self.times.fetch_add(1, Ordering::Relaxed);
        let mut lograte = self.lograte.load(Ordering::Relaxed);
        if lograte == 0 {
            lograte = Counter::default_log_rate();
            self.lograte.store(lograte, Ordering::Relaxed);
        }
        if times % lograte == 0 && times > 0 {
            let lastlog = self.lastlog.load(Ordering::Relaxed);
            info!(
                "COUNTER:{{\"name\": \"{}\", \"counts\": {}, \"samples\": {},  \"now\": {}, \"events\": {}}}",
                self.name,
                counts + events,
                times,
                timing::timestamp(),
                events,
            );
            metrics::submit(
                influxdb::Point::new(&format!("counter-{}", self.name))
                    .add_field(
                        "count",
                        influxdb::Value::Integer(counts as i64 - lastlog as i64),
                    ).to_owned(),
            );
            self.lastlog
                .compare_and_swap(lastlog, counts, Ordering::Relaxed);
        }
    }
}