use std::{collections::HashMap, sync::Arc};
use crate::common::Matcher;
use metrics_util::{Histogram, Quantile, Summary};
#[derive(Clone)]
pub enum Distribution {
Histogram(Histogram),
Summary(Summary, Arc<Vec<Quantile>>, f64),
}
impl Distribution {
pub fn new_histogram(buckets: &[f64]) -> Distribution {
let hist = Histogram::new(buckets).expect("buckets should never be empty");
Distribution::Histogram(hist)
}
pub fn new_summary(quantiles: Arc<Vec<Quantile>>) -> Distribution {
let summary = Summary::with_defaults();
Distribution::Summary(summary, quantiles, 0.0)
}
pub fn record_samples(&mut self, samples: &[f64]) {
match self {
Distribution::Histogram(hist) => hist.record_many(samples),
Distribution::Summary(hist, _, sum) => {
for sample in samples {
hist.add(*sample);
*sum += *sample;
}
}
}
}
}
#[derive(Debug)]
pub struct DistributionBuilder {
quantiles: Arc<Vec<Quantile>>,
buckets: Option<Vec<f64>>,
bucket_overrides: Option<Vec<(Matcher, Vec<f64>)>>,
}
impl DistributionBuilder {
pub fn new(
quantiles: Vec<Quantile>,
buckets: Option<Vec<f64>>,
bucket_overrides: Option<HashMap<Matcher, Vec<f64>>>,
) -> DistributionBuilder {
DistributionBuilder {
quantiles: Arc::new(quantiles),
buckets,
bucket_overrides: bucket_overrides.map(|entries| {
let mut matchers = entries.into_iter().collect::<Vec<_>>();
matchers.sort_by(|a, b| a.0.cmp(&b.0));
matchers
}),
}
}
pub fn get_distribution(&self, name: &str) -> Distribution {
if let Some(ref overrides) = self.bucket_overrides {
for (matcher, buckets) in overrides.iter() {
if matcher.matches(name) {
return Distribution::new_histogram(buckets);
}
}
}
if let Some(ref buckets) = self.buckets {
return Distribution::new_histogram(buckets);
}
Distribution::new_summary(self.quantiles.clone())
}
pub fn get_distribution_type(&self, name: &str) -> &str {
if self.buckets.is_some() {
return "histogram";
}
if let Some(ref overrides) = self.bucket_overrides {
for (matcher, _) in overrides.iter() {
if matcher.matches(name) {
return "histogram";
}
}
}
"summary"
}
}