1use std::{
2 fmt::{self, Display},
3 hash::Hash,
4};
5
6pub mod counter;
7pub mod gauge;
8pub mod histogram;
9pub mod snapshot;
10
11pub(crate) use self::{counter::Counter, gauge::Gauge, histogram::Histogram, snapshot::Snapshot};
12
13#[derive(Debug)]
17pub(crate) enum Sample<T> {
18 Count(T, i64),
23
24 Gauge(T, u64),
31
32 TimingHistogram(T, u64, u64, u64),
39
40 ValueHistogram(T, u64),
47}
48
49#[derive(Clone, Hash, PartialEq, Eq, Debug)]
51pub(crate) struct ScopedKey<T: Clone + Eq + Hash + Display>(u64, T);
52
53impl<T: Clone + Eq + Hash + Display> ScopedKey<T> {
54 pub(crate) fn id(&self) -> u64 { self.0 }
55
56 pub(crate) fn into_string_scoped(self, scope: String) -> StringScopedKey<T> { StringScopedKey(scope, self.1) }
57}
58
59#[derive(Clone, Hash, PartialEq, Eq, Debug)]
61pub(crate) struct StringScopedKey<T: Clone + Eq + Hash + Display>(String, T);
62
63impl<T: Clone + Hash + Eq + Display> Display for StringScopedKey<T> {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 if self.0.is_empty() {
66 write!(f, "{}", self.1)
67 } else {
68 write!(f, "{}.{}", self.0, self.1)
69 }
70 }
71}
72
73impl<T: Clone + Eq + Hash + Display> Sample<T> {
74 pub(crate) fn into_scoped(self, scope_id: u64) -> Sample<ScopedKey<T>> {
75 match self {
76 Sample::Count(key, value) => Sample::Count(ScopedKey(scope_id, key), value),
77 Sample::Gauge(key, value) => Sample::Gauge(ScopedKey(scope_id, key), value),
78 Sample::TimingHistogram(key, start, end, count) => {
79 Sample::TimingHistogram(ScopedKey(scope_id, key), start, end, count)
80 },
81 Sample::ValueHistogram(key, count) => Sample::ValueHistogram(ScopedKey(scope_id, key), count),
82 }
83 }
84}
85
86#[derive(Derivative, Debug, Clone)]
91#[derivative(Hash, PartialEq)]
92pub struct Percentile {
93 label: String,
94
95 #[derivative(Hash = "ignore")]
96 #[derivative(PartialEq = "ignore")]
97 value: f64,
98}
99
100impl Percentile {
101 pub fn label(&self) -> &str { self.label.as_str() }
106
107 pub fn percentile(&self) -> f64 { self.value }
109
110 pub fn as_quantile(&self) -> f64 { self.value / 100.0 }
112}
113
114impl Eq for Percentile {}
115
116impl From<f64> for Percentile {
117 fn from(p: f64) -> Self {
118 let clamped = p.max(0.0);
120 let clamped = clamped.min(100.0);
121
122 let raw_label = format!("{}", clamped);
123 let label = match raw_label.as_str() {
124 "0" => "min".to_string(),
125 "100" => "max".to_string(),
126 _ => {
127 let raw = format!("p{}", clamped);
128 raw.replace(".", "")
129 },
130 };
131
132 Percentile { label, value: clamped }
133 }
134}