use std::cmp;
use std::fmt;
use std::sync::mpsc;
use std::sync::Mutex;
use metric::{Metric, MetricFamilies, MetricFamily};
use Collect;
lazy_static! {
static ref DEFAULT_GATHERER: Mutex<Gatherer> = Mutex::new(Gatherer::new());
}
pub fn default_gatherer() -> &'static Mutex<Gatherer> {
&DEFAULT_GATHERER
}
pub fn default_registry() -> Registry {
if let Ok(gatherer) = default_gatherer().lock() {
gatherer.registry()
} else {
let (tx, _) = mpsc::channel();
Registry { tx }
}
}
#[derive(Debug, Clone)]
pub struct Registry {
tx: mpsc::Sender<Collector>,
}
impl Registry {
pub fn register<C>(&self, mut collector: C)
where
C: Collect + Send + 'static,
{
let f = move |metrics: &mut Vec<Metric>| {
if let Some(m) = collector.collect() {
metrics.extend(m);
true
} else {
false
}
};
let _ = self.tx.send(Collector(Box::new(f)));
}
}
struct Collector(Box<dyn FnMut(&mut Vec<Metric>) -> bool + Send + 'static>);
impl Collector {
fn collect(&mut self, metrics: &mut Vec<Metric>) -> bool {
(self.0)(metrics)
}
}
impl fmt::Debug for Collector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Collector(_)")
}
}
#[derive(Debug)]
pub struct Gatherer {
tx: mpsc::Sender<Collector>,
rx: mpsc::Receiver<Collector>,
collectors: Vec<Collector>,
}
impl Gatherer {
pub fn new() -> Self {
let (tx, rx) = mpsc::channel();
Gatherer {
tx,
rx,
collectors: Vec::new(),
}
}
pub fn registry(&self) -> Registry {
Registry {
tx: self.tx.clone(),
}
}
pub fn gather(&mut self) -> MetricFamilies {
while let Ok(collector) = self.rx.try_recv() {
self.collectors.push(collector);
}
let mut metrics = Vec::new();
let mut i = 0;
while i < self.collectors.len() {
if self.collectors[i].collect(&mut metrics) {
i += 1;
} else {
self.collectors.swap_remove(i);
}
}
metrics.sort_by(|a, b| {
let result = (a.name(), a.kind()).cmp(&(b.name(), b.kind()));
if result == cmp::Ordering::Equal {
a.labels().iter().cmp(b.labels().iter())
} else {
result
}
});
let mut families: Vec<MetricFamily> = Vec::new();
for metric in metrics {
if !families.last().map_or(false, |f| f.same_family(&metric)) {
families.push(MetricFamily::new(metric));
} else {
families.last_mut().unwrap().push(metric);
}
}
MetricFamilies(families)
}
}
impl Default for Gatherer {
fn default() -> Self {
Self::new()
}
}