use std::time::{Duration, Instant};
use self::switches::*;
use snapshot::{ItemKind, Snapshot};
use util;
use Observation;
use {Descriptive, PutsSnapshot};
pub use self::counter::Counter;
pub use self::gauge::Gauge;
pub use self::histogram::Histogram;
pub use self::meter::Meter;
mod counter;
mod gauge;
mod histogram;
mod meter;
pub mod other_instruments;
pub mod polled;
pub mod switches;
#[derive(Debug, Clone, Copy)]
pub enum ValueScaling {
NanosToMillis,
NanosToMicros,
}
#[derive(Debug, Clone)]
pub enum Update {
Observations(u64, Instant),
Observation(Instant),
ObservationWithValue(u64, Instant),
}
impl Update {
pub fn scale(self, scaling: ValueScaling) -> Update {
if let Update::ObservationWithValue(v, t) = self {
match scaling {
ValueScaling::NanosToMillis => Update::ObservationWithValue(v / 1_000_000, t),
ValueScaling::NanosToMicros => Update::ObservationWithValue(v / 1_000, t),
}
} else {
self
}
}
}
pub struct LabelAndUpdate<T>(pub T, pub Update);
impl<T> From<Observation<T>> for LabelAndUpdate<T> {
fn from(obs: Observation<T>) -> LabelAndUpdate<T> {
match obs {
Observation::Observed {
label,
count,
timestamp,
..
} => LabelAndUpdate(label, Update::Observations(count, timestamp)),
Observation::ObservedOne {
label, timestamp, ..
} => LabelAndUpdate(label, Update::Observation(timestamp)),
Observation::ObservedOneValue {
label,
value,
timestamp,
..
} => LabelAndUpdate(label, Update::ObservationWithValue(value, timestamp)),
}
}
}
pub struct BorrowedLabelAndUpdate<'a, T: 'a>(pub &'a T, pub Update);
impl<'a, T> From<&'a Observation<T>> for BorrowedLabelAndUpdate<'a, T> {
fn from(obs: &'a Observation<T>) -> BorrowedLabelAndUpdate<'a, T> {
match obs {
Observation::Observed {
label,
count,
timestamp,
..
} => BorrowedLabelAndUpdate(label, Update::Observations(*count, *timestamp)),
Observation::ObservedOne {
label, timestamp, ..
} => BorrowedLabelAndUpdate(label, Update::Observation(*timestamp)),
Observation::ObservedOneValue {
label,
value,
timestamp,
..
} => BorrowedLabelAndUpdate(label, Update::ObservationWithValue(*value, *timestamp)),
}
}
}
pub trait Updates {
fn update(&mut self, with: &Update) -> usize;
}
pub trait Instrument: Updates + PutsSnapshot {}
pub struct Panel<L> {
label: L,
name: Option<String>,
title: Option<String>,
description: Option<String>,
counter: Option<Counter>,
gauge: Option<Gauge>,
meter: Option<Meter>,
histogram: Option<Histogram>,
instruments: Vec<Box<Instrument>>,
snapshooters: Vec<Box<PutsSnapshot>>,
value_scaling: Option<ValueScaling>,
last_update: Instant,
max_inactivity_duration: Option<Duration>,
}
impl<L> Panel<L> {
pub fn new(label: L) -> Panel<L> {
Panel {
label,
name: None,
title: None,
description: None,
counter: None,
gauge: None,
meter: None,
histogram: None,
value_scaling: None,
instruments: Vec::new(),
snapshooters: Vec::new(),
last_update: Instant::now(),
max_inactivity_duration: None,
}
}
pub fn with_name<T: Into<String>>(label: L, name: T) -> Panel<L> {
let mut panel = Panel::new(label);
panel.set_name(name);
panel
}
pub fn set_counter(&mut self, counter: Counter) {
self.counter = Some(counter);
}
pub fn counter(&self) -> Option<&Counter> {
self.counter.as_ref()
}
pub fn set_gauge(&mut self, gauge: Gauge) {
self.gauge = Some(gauge);
}
pub fn gauge(&self) -> Option<&Gauge> {
self.gauge.as_ref()
}
pub fn set_meter(&mut self, meter: Meter) {
self.meter = Some(meter);
}
pub fn meter(&self) -> Option<&Meter> {
self.meter.as_ref()
}
pub fn set_histogram(&mut self, histogram: Histogram) {
self.histogram = Some(histogram);
}
pub fn histogram(&self) -> Option<&Histogram> {
self.histogram.as_ref()
}
#[deprecated(since = "0.6.0", note = "use add_instrument")]
pub fn set_staircase_timer(&mut self, timer: StaircaseTimer) {
self.add_instrument(timer);
}
#[deprecated(since = "0.6.0", note = "there will be no replacement")]
pub fn staircase_timer(&self) -> Option<&StaircaseTimer> {
None
}
pub fn add_snapshooter<T: PutsSnapshot>(&mut self, snapshooter: T) {
self.snapshooters.push(Box::new(snapshooter));
}
pub fn snapshooters(&self) -> Vec<&PutsSnapshot> {
self.snapshooters.iter().map(|p| &**p).collect()
}
pub fn add_instrument<I: Instrument>(&mut self, instrument: I) {
self.instruments.push(Box::new(instrument));
}
pub fn instruments(&self) -> Vec<&Instrument> {
self.instruments.iter().map(|p| &**p).collect()
}
pub fn set_value_scaling(&mut self, value_scaling: ValueScaling) {
self.value_scaling = Some(value_scaling)
}
pub fn name(&self) -> Option<&str> {
self.name.as_ref().map(|n| &**n)
}
pub fn set_name<T: Into<String>>(&mut self, name: T) {
self.name = Some(name.into());
}
pub fn set_title<T: Into<String>>(&mut self, title: T) {
self.title = Some(title.into())
}
pub fn set_description<T: Into<String>>(&mut self, description: T) {
self.description = Some(description.into())
}
pub fn set_inactivity_limit(&mut self, limit: Duration) {
self.max_inactivity_duration = Some(limit);
}
pub fn label(&self) -> &L {
&self.label
}
fn put_values_into_snapshot(&self, into: &mut Snapshot, descriptive: bool) {
util::put_default_descriptives(self, into, descriptive);
if let Some(d) = self.max_inactivity_duration {
if self.last_update.elapsed() > d {
into.items
.push(("_inactive".to_string(), ItemKind::Boolean(true)));
into.items
.push(("_active".to_string(), ItemKind::Boolean(false)));
return;
} else {
into.items
.push(("_inactive".to_string(), ItemKind::Boolean(false)));
into.items
.push(("_active".to_string(), ItemKind::Boolean(true)));
}
};
self.counter
.as_ref()
.iter()
.for_each(|x| x.put_snapshot(into, descriptive));
self.gauge
.as_ref()
.iter()
.for_each(|x| x.put_snapshot(into, descriptive));
self.meter
.as_ref()
.iter()
.for_each(|x| x.put_snapshot(into, descriptive));
self.histogram
.as_ref()
.iter()
.for_each(|x| x.put_snapshot(into, descriptive));
self.snapshooters
.iter()
.for_each(|p| p.put_snapshot(into, descriptive));
self.instruments
.iter()
.for_each(|p| p.put_snapshot(into, descriptive));
}
}
impl<L> PutsSnapshot for Panel<L>
where
L: Send + 'static,
{
fn put_snapshot(&self, into: &mut Snapshot, descriptive: bool) {
if let Some(ref name) = self.name {
let mut new_level = Snapshot::default();
self.put_values_into_snapshot(&mut new_level, descriptive);
into.items
.push((name.clone(), ItemKind::Snapshot(new_level)));
} else {
self.put_values_into_snapshot(into, descriptive);
}
}
}
impl<L> Updates for Panel<L> {
fn update(&mut self, with: &Update) -> usize {
let mut instruments_updated = 0;
let with = if let Some(scaling) = self.value_scaling {
with.clone().scale(scaling)
} else {
with.clone()
};
self.counter
.iter_mut()
.for_each(|x| instruments_updated += x.update(&with));
self.gauge
.iter_mut()
.for_each(|x| instruments_updated += x.update(&with));
self.meter
.iter_mut()
.for_each(|x| instruments_updated += x.update(&with));
self.histogram
.iter_mut()
.for_each(|x| instruments_updated += x.update(&with));
self.instruments
.iter_mut()
.for_each(|x| instruments_updated += x.update(&with));
if instruments_updated != 0 {
self.last_update = Instant::now();
}
instruments_updated
}
}
impl<L> Descriptive for Panel<L> {
fn title(&self) -> Option<&str> {
self.title.as_ref().map(|n| &**n)
}
fn description(&self) -> Option<&str> {
self.description.as_ref().map(|n| &**n)
}
}