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
15pub(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
23pub(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 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 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>, }
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}