use std::{
fmt::{self, Display},
hash::Hash,
};
pub mod counter;
pub mod gauge;
pub mod histogram;
pub mod snapshot;
pub(crate) use self::{counter::Counter, gauge::Gauge, histogram::Histogram, snapshot::Snapshot};
#[derive(Debug)]
pub(crate) enum Sample<T> {
Count(T, i64),
Gauge(T, u64),
TimingHistogram(T, u64, u64, u64),
ValueHistogram(T, u64),
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub(crate) struct ScopedKey<T: Clone + Eq + Hash + Display>(u64, T);
impl<T: Clone + Eq + Hash + Display> ScopedKey<T> {
pub(crate) fn id(&self) -> u64 { self.0 }
pub(crate) fn into_string_scoped(self, scope: String) -> StringScopedKey<T> { StringScopedKey(scope, self.1) }
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub(crate) struct StringScopedKey<T: Clone + Eq + Hash + Display>(String, T);
impl<T: Clone + Hash + Eq + Display> Display for StringScopedKey<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.0.is_empty() {
write!(f, "{}", self.1)
} else {
write!(f, "{}.{}", self.0, self.1)
}
}
}
impl<T: Clone + Eq + Hash + Display> Sample<T> {
pub(crate) fn into_scoped(self, scope_id: u64) -> Sample<ScopedKey<T>> {
match self {
Sample::Count(key, value) => Sample::Count(ScopedKey(scope_id, key), value),
Sample::Gauge(key, value) => Sample::Gauge(ScopedKey(scope_id, key), value),
Sample::TimingHistogram(key, start, end, count) => {
Sample::TimingHistogram(ScopedKey(scope_id, key), start, end, count)
},
Sample::ValueHistogram(key, count) => Sample::ValueHistogram(ScopedKey(scope_id, key), count),
}
}
}
#[derive(Derivative, Debug, Clone)]
#[derivative(Hash, PartialEq)]
pub struct Percentile {
label: String,
#[derivative(Hash = "ignore")]
#[derivative(PartialEq = "ignore")]
value: f64,
}
impl Percentile {
pub fn label(&self) -> &str { self.label.as_str() }
pub fn percentile(&self) -> f64 { self.value }
pub fn as_quantile(&self) -> f64 { self.value / 100.0 }
}
impl Eq for Percentile {}
impl From<f64> for Percentile {
fn from(p: f64) -> Self {
let clamped = p.max(0.0);
let clamped = clamped.min(100.0);
let raw_label = format!("{}", clamped);
let label = match raw_label.as_str() {
"0" => "min".to_string(),
"100" => "max".to_string(),
_ => {
let raw = format!("p{}", clamped);
raw.replace(".", "")
},
};
Percentile { label, value: clamped }
}
}