opentelemetry/metrics/
mod.rs

1//! # OpenTelemetry Metrics API
2
3use std::hash::{Hash, Hasher};
4use std::sync::Arc;
5
6mod instruments;
7mod meter;
8pub(crate) mod noop;
9
10use crate::{Array, KeyValue, Value};
11pub use instruments::{
12    counter::{Counter, ObservableCounter},
13    gauge::{Gauge, ObservableGauge},
14    histogram::Histogram,
15    up_down_counter::{ObservableUpDownCounter, UpDownCounter},
16    AsyncInstrument, AsyncInstrumentBuilder, Callback, HistogramBuilder, InstrumentBuilder,
17    SyncInstrument,
18};
19pub use meter::{Meter, MeterProvider};
20
21struct F64Hashable(f64);
22
23impl PartialEq for F64Hashable {
24    fn eq(&self, other: &Self) -> bool {
25        self.0.to_bits() == other.0.to_bits()
26    }
27}
28
29impl Eq for F64Hashable {}
30
31impl Hash for F64Hashable {
32    fn hash<H: Hasher>(&self, state: &mut H) {
33        self.0.to_bits().hash(state);
34    }
35}
36
37impl Hash for KeyValue {
38    fn hash<H: Hasher>(&self, state: &mut H) {
39        self.key.hash(state);
40        match &self.value {
41            Value::F64(f) => F64Hashable(*f).hash(state),
42            Value::Array(a) => match a {
43                Array::Bool(b) => b.hash(state),
44                Array::I64(i) => i.hash(state),
45                Array::F64(f) => f.iter().for_each(|f| F64Hashable(*f).hash(state)),
46                Array::String(s) => s.hash(state),
47            },
48            Value::Bool(b) => b.hash(state),
49            Value::I64(i) => i.hash(state),
50            Value::String(s) => s.hash(state),
51        };
52    }
53}
54
55impl Eq for KeyValue {}
56
57/// SDK implemented trait for creating instruments
58pub trait InstrumentProvider {
59    /// creates an instrument for recording increasing values.
60    fn u64_counter(&self, _builder: InstrumentBuilder<'_, Counter<u64>>) -> Counter<u64> {
61        Counter::new(Arc::new(noop::NoopSyncInstrument::new()))
62    }
63
64    /// creates an instrument for recording increasing values.
65    fn f64_counter(&self, _builder: InstrumentBuilder<'_, Counter<f64>>) -> Counter<f64> {
66        Counter::new(Arc::new(noop::NoopSyncInstrument::new()))
67    }
68
69    /// creates an instrument for recording increasing values via callback.
70    fn u64_observable_counter(
71        &self,
72        _builder: AsyncInstrumentBuilder<'_, ObservableCounter<u64>, u64>,
73    ) -> ObservableCounter<u64> {
74        ObservableCounter::new()
75    }
76
77    /// creates an instrument for recording increasing values via callback.
78    fn f64_observable_counter(
79        &self,
80        _builder: AsyncInstrumentBuilder<'_, ObservableCounter<f64>, f64>,
81    ) -> ObservableCounter<f64> {
82        ObservableCounter::new()
83    }
84
85    /// creates an instrument for recording changes of a value.
86    fn i64_up_down_counter(
87        &self,
88        _builder: InstrumentBuilder<'_, UpDownCounter<i64>>,
89    ) -> UpDownCounter<i64> {
90        UpDownCounter::new(Arc::new(noop::NoopSyncInstrument::new()))
91    }
92
93    /// creates an instrument for recording changes of a value.
94    fn f64_up_down_counter(
95        &self,
96        _builder: InstrumentBuilder<'_, UpDownCounter<f64>>,
97    ) -> UpDownCounter<f64> {
98        UpDownCounter::new(Arc::new(noop::NoopSyncInstrument::new()))
99    }
100
101    /// creates an instrument for recording changes of a value.
102    fn i64_observable_up_down_counter(
103        &self,
104        _builder: AsyncInstrumentBuilder<'_, ObservableUpDownCounter<i64>, i64>,
105    ) -> ObservableUpDownCounter<i64> {
106        ObservableUpDownCounter::new()
107    }
108
109    /// creates an instrument for recording changes of a value via callback.
110    fn f64_observable_up_down_counter(
111        &self,
112        _builder: AsyncInstrumentBuilder<'_, ObservableUpDownCounter<f64>, f64>,
113    ) -> ObservableUpDownCounter<f64> {
114        ObservableUpDownCounter::new()
115    }
116
117    /// creates an instrument for recording independent values.
118    fn u64_gauge(&self, _builder: InstrumentBuilder<'_, Gauge<u64>>) -> Gauge<u64> {
119        Gauge::new(Arc::new(noop::NoopSyncInstrument::new()))
120    }
121
122    /// creates an instrument for recording independent values.
123    fn f64_gauge(&self, _builder: InstrumentBuilder<'_, Gauge<f64>>) -> Gauge<f64> {
124        Gauge::new(Arc::new(noop::NoopSyncInstrument::new()))
125    }
126
127    /// creates an instrument for recording independent values.
128    fn i64_gauge(&self, _builder: InstrumentBuilder<'_, Gauge<i64>>) -> Gauge<i64> {
129        Gauge::new(Arc::new(noop::NoopSyncInstrument::new()))
130    }
131
132    /// creates an instrument for recording the current value via callback.
133    fn u64_observable_gauge(
134        &self,
135        _builder: AsyncInstrumentBuilder<'_, ObservableGauge<u64>, u64>,
136    ) -> ObservableGauge<u64> {
137        ObservableGauge::new()
138    }
139
140    /// creates an instrument for recording the current value via callback.
141    fn i64_observable_gauge(
142        &self,
143        _builder: AsyncInstrumentBuilder<'_, ObservableGauge<i64>, i64>,
144    ) -> ObservableGauge<i64> {
145        ObservableGauge::new()
146    }
147
148    /// creates an instrument for recording the current value via callback.
149    fn f64_observable_gauge(
150        &self,
151        _builder: AsyncInstrumentBuilder<'_, ObservableGauge<f64>, f64>,
152    ) -> ObservableGauge<f64> {
153        ObservableGauge::new()
154    }
155
156    /// creates an instrument for recording a distribution of values.
157    fn f64_histogram(&self, _builder: HistogramBuilder<'_, Histogram<f64>>) -> Histogram<f64> {
158        Histogram::new(Arc::new(noop::NoopSyncInstrument::new()))
159    }
160
161    /// creates an instrument for recording a distribution of values.
162    fn u64_histogram(&self, _builder: HistogramBuilder<'_, Histogram<u64>>) -> Histogram<u64> {
163        Histogram::new(Arc::new(noop::NoopSyncInstrument::new()))
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use rand::Rng;
170
171    use crate::KeyValue;
172    use std::collections::hash_map::DefaultHasher;
173    use std::f64;
174    use std::hash::{Hash, Hasher};
175
176    #[test]
177    fn kv_float_equality() {
178        let kv1 = KeyValue::new("key", 1.0);
179        let kv2 = KeyValue::new("key", 1.0);
180        assert_eq!(kv1, kv2);
181
182        let kv1 = KeyValue::new("key", 1.0);
183        let kv2 = KeyValue::new("key", 1.01);
184        assert_ne!(kv1, kv2);
185
186        let kv1 = KeyValue::new("key", f64::NAN);
187        let kv2 = KeyValue::new("key", f64::NAN);
188        assert_ne!(kv1, kv2, "NAN is not equal to itself");
189
190        for float_val in [
191            f64::INFINITY,
192            f64::NEG_INFINITY,
193            f64::MAX,
194            f64::MIN,
195            f64::MIN_POSITIVE,
196        ]
197        .iter()
198        {
199            let kv1 = KeyValue::new("key", *float_val);
200            let kv2 = KeyValue::new("key", *float_val);
201            assert_eq!(kv1, kv2);
202        }
203
204        let mut rng = rand::thread_rng();
205
206        for _ in 0..100 {
207            let random_value = rng.gen::<f64>();
208            let kv1 = KeyValue::new("key", random_value);
209            let kv2 = KeyValue::new("key", random_value);
210            assert_eq!(kv1, kv2);
211        }
212    }
213
214    #[test]
215    fn kv_float_hash() {
216        for float_val in [
217            f64::NAN,
218            f64::INFINITY,
219            f64::NEG_INFINITY,
220            f64::MAX,
221            f64::MIN,
222            f64::MIN_POSITIVE,
223        ]
224        .iter()
225        {
226            let kv1 = KeyValue::new("key", *float_val);
227            let kv2 = KeyValue::new("key", *float_val);
228            assert_eq!(hash_helper(&kv1), hash_helper(&kv2));
229        }
230
231        let mut rng = rand::thread_rng();
232
233        for _ in 0..100 {
234            let random_value = rng.gen::<f64>();
235            let kv1 = KeyValue::new("key", random_value);
236            let kv2 = KeyValue::new("key", random_value);
237            assert_eq!(hash_helper(&kv1), hash_helper(&kv2));
238        }
239    }
240
241    fn hash_helper<T: Hash>(item: &T) -> u64 {
242        let mut hasher = DefaultHasher::new();
243        item.hash(&mut hasher);
244        hasher.finish()
245    }
246}