opentelemetry_sdk/metrics/internal/
mod.rs

1mod aggregate;
2mod exponential_histogram;
3mod histogram;
4mod last_value;
5mod sum;
6
7use core::fmt;
8use std::ops::{Add, AddAssign, Sub};
9use std::sync::atomic::{AtomicI64, AtomicU64, Ordering};
10use std::sync::Mutex;
11
12pub(crate) use aggregate::{AggregateBuilder, ComputeAggregation, Measure};
13pub(crate) use exponential_histogram::{EXPO_MAX_SCALE, EXPO_MIN_SCALE};
14
15/// Marks a type that can have a value added and retrieved atomically. Required since
16/// different types have different backing atomic mechanisms
17pub(crate) trait AtomicTracker<T>: Sync + Send + 'static {
18    fn add(&self, value: T);
19    fn get_value(&self) -> T;
20    fn get_and_reset_value(&self) -> T;
21}
22
23/// Marks a type that can have an atomic tracker generated for it
24pub(crate) trait AtomicallyUpdate<T> {
25    type AtomicTracker: AtomicTracker<T>;
26    fn new_atomic_tracker() -> Self::AtomicTracker;
27}
28
29pub(crate) trait Number<T>:
30    Add<Output = T>
31    + AddAssign
32    + Sub<Output = T>
33    + PartialOrd
34    + fmt::Debug
35    + Clone
36    + Copy
37    + PartialEq
38    + Default
39    + Send
40    + Sync
41    + 'static
42    + AtomicallyUpdate<T>
43{
44    fn min() -> Self;
45    fn max() -> Self;
46
47    fn into_float(self) -> f64;
48}
49
50impl Number<i64> for i64 {
51    fn min() -> Self {
52        i64::MIN
53    }
54
55    fn max() -> Self {
56        i64::MAX
57    }
58
59    fn into_float(self) -> f64 {
60        // May have precision loss at high values
61        self as f64
62    }
63}
64impl Number<u64> for u64 {
65    fn min() -> Self {
66        u64::MIN
67    }
68
69    fn max() -> Self {
70        u64::MAX
71    }
72
73    fn into_float(self) -> f64 {
74        // May have precision loss at high values
75        self as f64
76    }
77}
78impl Number<f64> for f64 {
79    fn min() -> Self {
80        f64::MIN
81    }
82
83    fn max() -> Self {
84        f64::MAX
85    }
86
87    fn into_float(self) -> f64 {
88        self
89    }
90}
91
92impl AtomicTracker<u64> for AtomicU64 {
93    fn add(&self, value: u64) {
94        self.fetch_add(value, Ordering::Relaxed);
95    }
96
97    fn get_value(&self) -> u64 {
98        self.load(Ordering::Relaxed)
99    }
100
101    fn get_and_reset_value(&self) -> u64 {
102        self.swap(0, Ordering::Relaxed)
103    }
104}
105
106impl AtomicallyUpdate<u64> for u64 {
107    type AtomicTracker = AtomicU64;
108
109    fn new_atomic_tracker() -> Self::AtomicTracker {
110        AtomicU64::new(0)
111    }
112}
113
114impl AtomicTracker<i64> for AtomicI64 {
115    fn add(&self, value: i64) {
116        self.fetch_add(value, Ordering::Relaxed);
117    }
118
119    fn get_value(&self) -> i64 {
120        self.load(Ordering::Relaxed)
121    }
122
123    fn get_and_reset_value(&self) -> i64 {
124        self.swap(0, Ordering::Relaxed)
125    }
126}
127
128impl AtomicallyUpdate<i64> for i64 {
129    type AtomicTracker = AtomicI64;
130
131    fn new_atomic_tracker() -> Self::AtomicTracker {
132        AtomicI64::new(0)
133    }
134}
135
136pub(crate) struct F64AtomicTracker {
137    inner: Mutex<f64>, // Floating points don't have true atomics, so we need to use mutex for them
138}
139
140impl F64AtomicTracker {
141    fn new() -> Self {
142        F64AtomicTracker {
143            inner: Mutex::new(0.0),
144        }
145    }
146}
147
148impl AtomicTracker<f64> for F64AtomicTracker {
149    fn add(&self, value: f64) {
150        let mut guard = self.inner.lock().expect("F64 mutex was poisoned");
151        *guard += value;
152    }
153
154    fn get_value(&self) -> f64 {
155        let guard = self.inner.lock().expect("F64 mutex was poisoned");
156        *guard
157    }
158
159    fn get_and_reset_value(&self) -> f64 {
160        let mut guard = self.inner.lock().expect("F64 mutex was poisoned");
161        let value = *guard;
162        *guard = 0.0;
163
164        value
165    }
166}
167
168impl AtomicallyUpdate<f64> for f64 {
169    type AtomicTracker = F64AtomicTracker;
170
171    fn new_atomic_tracker() -> Self::AtomicTracker {
172        F64AtomicTracker::new()
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179
180    #[test]
181    fn can_add_and_get_u64_atomic_value() {
182        let atomic = u64::new_atomic_tracker();
183        atomic.add(15);
184        atomic.add(10);
185
186        let value = atomic.get_value();
187        assert_eq!(value, 25);
188    }
189
190    #[test]
191    fn can_reset_u64_atomic_value() {
192        let atomic = u64::new_atomic_tracker();
193        atomic.add(15);
194
195        let value = atomic.get_and_reset_value();
196        let value2 = atomic.get_value();
197
198        assert_eq!(value, 15, "Incorrect first value");
199        assert_eq!(value2, 0, "Incorrect second value");
200    }
201
202    #[test]
203    fn can_add_and_get_i64_atomic_value() {
204        let atomic = i64::new_atomic_tracker();
205        atomic.add(15);
206        atomic.add(-10);
207
208        let value = atomic.get_value();
209        assert_eq!(value, 5);
210    }
211
212    #[test]
213    fn can_reset_i64_atomic_value() {
214        let atomic = i64::new_atomic_tracker();
215        atomic.add(15);
216
217        let value = atomic.get_and_reset_value();
218        let value2 = atomic.get_value();
219
220        assert_eq!(value, 15, "Incorrect first value");
221        assert_eq!(value2, 0, "Incorrect second value");
222    }
223
224    #[test]
225    fn can_add_and_get_f64_atomic_value() {
226        let atomic = f64::new_atomic_tracker();
227        atomic.add(15.3);
228        atomic.add(10.4);
229
230        let value = atomic.get_value();
231
232        assert!(f64::abs(25.7 - value) < 0.0001);
233    }
234
235    #[test]
236    fn can_reset_f64_atomic_value() {
237        let atomic = f64::new_atomic_tracker();
238        atomic.add(15.5);
239
240        let value = atomic.get_and_reset_value();
241        let value2 = atomic.get_value();
242
243        assert!(f64::abs(15.5 - value) < 0.0001, "Incorrect first value");
244        assert!(f64::abs(0.0 - value2) < 0.0001, "Incorrect second value");
245    }
246}