Skip to content

Commit 43cd4ac

Browse files
committed
Fix delta aggregation metric reuse (#1434)
1 parent 3ed8998 commit 43cd4ac

File tree

6 files changed

+396
-294
lines changed

6 files changed

+396
-294
lines changed

opentelemetry-sdk/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## vNext
44

5+
- Fix delta aggregation metric reuse. (#1434)
6+
7+
## v0.21.1
8+
59
### Fixed
610

711
- Fix metric export corruption if gauges have not received a last value. (#1363)

opentelemetry-sdk/src/metrics/internal/aggregate.rs

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,239 @@ impl<T: Number<T>> AggregateBuilder<T> {
210210
)
211211
}
212212
}
213+
214+
#[cfg(test)]
215+
mod tests {
216+
use crate::metrics::data::{
217+
DataPoint, ExponentialBucket, ExponentialHistogram, ExponentialHistogramDataPoint,
218+
Histogram, HistogramDataPoint, Sum,
219+
};
220+
use std::time::SystemTime;
221+
222+
use super::*;
223+
224+
#[test]
225+
fn last_value_aggregation() {
226+
let (measure, agg) = AggregateBuilder::<u64>::new(None, None).last_value();
227+
let mut a = Gauge {
228+
data_points: vec![DataPoint {
229+
attributes: AttributeSet::from(&[KeyValue::new("a", 1)][..]),
230+
start_time: Some(SystemTime::now()),
231+
time: Some(SystemTime::now()),
232+
value: 1u64,
233+
exemplars: vec![],
234+
}],
235+
};
236+
let new_attributes = [KeyValue::new("b", 2)];
237+
measure.call(2, AttributeSet::from(&new_attributes[..]));
238+
239+
let (count, new_agg) = agg.call(Some(&mut a));
240+
241+
assert_eq!(count, 1);
242+
assert!(new_agg.is_none());
243+
assert_eq!(a.data_points.len(), 1);
244+
assert_eq!(
245+
a.data_points[0].attributes,
246+
AttributeSet::from(&new_attributes[..])
247+
);
248+
assert_eq!(a.data_points[0].value, 2);
249+
}
250+
251+
#[test]
252+
fn precomputed_sum_aggregation() {
253+
for temporality in [Temporality::Delta, Temporality::Cumulative] {
254+
let (measure, agg) =
255+
AggregateBuilder::<u64>::new(Some(temporality), None).precomputed_sum(true);
256+
let mut a = Sum {
257+
data_points: vec![
258+
DataPoint {
259+
attributes: AttributeSet::from(&[KeyValue::new("a1", 1)][..]),
260+
start_time: Some(SystemTime::now()),
261+
time: Some(SystemTime::now()),
262+
value: 1u64,
263+
exemplars: vec![],
264+
},
265+
DataPoint {
266+
attributes: AttributeSet::from(&[KeyValue::new("a2", 2)][..]),
267+
start_time: Some(SystemTime::now()),
268+
time: Some(SystemTime::now()),
269+
value: 2u64,
270+
exemplars: vec![],
271+
},
272+
],
273+
temporality: if temporality == Temporality::Delta {
274+
Temporality::Cumulative
275+
} else {
276+
Temporality::Delta
277+
},
278+
is_monotonic: false,
279+
};
280+
let new_attributes = [KeyValue::new("b", 2)];
281+
measure.call(3, AttributeSet::from(&new_attributes[..]));
282+
283+
let (count, new_agg) = agg.call(Some(&mut a));
284+
285+
assert_eq!(count, 1);
286+
assert!(new_agg.is_none());
287+
assert_eq!(a.temporality, temporality);
288+
assert!(a.is_monotonic);
289+
assert_eq!(a.data_points.len(), 1);
290+
assert_eq!(
291+
a.data_points[0].attributes,
292+
AttributeSet::from(&new_attributes[..])
293+
);
294+
assert_eq!(a.data_points[0].value, 3);
295+
}
296+
}
297+
298+
#[test]
299+
fn sum_aggregation() {
300+
for temporality in [Temporality::Delta, Temporality::Cumulative] {
301+
let (measure, agg) = AggregateBuilder::<u64>::new(Some(temporality), None).sum(true);
302+
let mut a = Sum {
303+
data_points: vec![
304+
DataPoint {
305+
attributes: AttributeSet::from(&[KeyValue::new("a1", 1)][..]),
306+
start_time: Some(SystemTime::now()),
307+
time: Some(SystemTime::now()),
308+
value: 1u64,
309+
exemplars: vec![],
310+
},
311+
DataPoint {
312+
attributes: AttributeSet::from(&[KeyValue::new("a2", 2)][..]),
313+
start_time: Some(SystemTime::now()),
314+
time: Some(SystemTime::now()),
315+
value: 2u64,
316+
exemplars: vec![],
317+
},
318+
],
319+
temporality: if temporality == Temporality::Delta {
320+
Temporality::Cumulative
321+
} else {
322+
Temporality::Delta
323+
},
324+
is_monotonic: false,
325+
};
326+
let new_attributes = [KeyValue::new("b", 2)];
327+
measure.call(3, AttributeSet::from(&new_attributes[..]));
328+
329+
let (count, new_agg) = agg.call(Some(&mut a));
330+
331+
assert_eq!(count, 1);
332+
assert!(new_agg.is_none());
333+
assert_eq!(a.temporality, temporality);
334+
assert!(a.is_monotonic);
335+
assert_eq!(a.data_points.len(), 1);
336+
assert_eq!(
337+
a.data_points[0].attributes,
338+
AttributeSet::from(&new_attributes[..])
339+
);
340+
assert_eq!(a.data_points[0].value, 3);
341+
}
342+
}
343+
344+
#[test]
345+
fn explicit_bucket_histogram_aggregation() {
346+
for temporality in [Temporality::Delta, Temporality::Cumulative] {
347+
let (measure, agg) = AggregateBuilder::<u64>::new(Some(temporality), None)
348+
.explicit_bucket_histogram(vec![1.0], true, true);
349+
let mut a = Histogram {
350+
data_points: vec![HistogramDataPoint {
351+
attributes: AttributeSet::from(&[KeyValue::new("a2", 2)][..]),
352+
start_time: SystemTime::now(),
353+
time: SystemTime::now(),
354+
count: 2,
355+
bounds: vec![1.0, 2.0],
356+
bucket_counts: vec![0, 1, 1],
357+
min: None,
358+
max: None,
359+
sum: 3u64,
360+
exemplars: vec![],
361+
}],
362+
temporality: if temporality == Temporality::Delta {
363+
Temporality::Cumulative
364+
} else {
365+
Temporality::Delta
366+
},
367+
};
368+
let new_attributes = [KeyValue::new("b", 2)];
369+
measure.call(3, AttributeSet::from(&new_attributes[..]));
370+
371+
let (count, new_agg) = agg.call(Some(&mut a));
372+
373+
assert_eq!(count, 1);
374+
assert!(new_agg.is_none());
375+
assert_eq!(a.temporality, temporality);
376+
assert_eq!(a.data_points.len(), 1);
377+
assert_eq!(
378+
a.data_points[0].attributes,
379+
AttributeSet::from(&new_attributes[..])
380+
);
381+
assert_eq!(a.data_points[0].count, 1);
382+
assert_eq!(a.data_points[0].bounds, vec![1.0]);
383+
assert_eq!(a.data_points[0].bucket_counts, vec![0, 1]);
384+
assert_eq!(a.data_points[0].min, Some(3));
385+
assert_eq!(a.data_points[0].max, Some(3));
386+
assert_eq!(a.data_points[0].sum, 3);
387+
}
388+
}
389+
390+
#[test]
391+
fn exponential_histogram_aggregation() {
392+
for temporality in [Temporality::Delta, Temporality::Cumulative] {
393+
let (measure, agg) = AggregateBuilder::<u64>::new(Some(temporality), None)
394+
.exponential_bucket_histogram(4, 20, true, true);
395+
let mut a = ExponentialHistogram {
396+
data_points: vec![ExponentialHistogramDataPoint {
397+
attributes: AttributeSet::from(&[KeyValue::new("a2", 2)][..]),
398+
start_time: SystemTime::now(),
399+
time: SystemTime::now(),
400+
count: 2,
401+
min: None,
402+
max: None,
403+
sum: 3u64,
404+
scale: 10,
405+
zero_count: 1,
406+
positive_bucket: ExponentialBucket {
407+
offset: 1,
408+
counts: vec![1],
409+
},
410+
negative_bucket: ExponentialBucket {
411+
offset: 1,
412+
counts: vec![1],
413+
},
414+
zero_threshold: 1.0,
415+
exemplars: vec![],
416+
}],
417+
temporality: if temporality == Temporality::Delta {
418+
Temporality::Cumulative
419+
} else {
420+
Temporality::Delta
421+
},
422+
};
423+
let new_attributes = [KeyValue::new("b", 2)];
424+
measure.call(3, AttributeSet::from(&new_attributes[..]));
425+
426+
let (count, new_agg) = agg.call(Some(&mut a));
427+
428+
assert_eq!(count, 1);
429+
assert!(new_agg.is_none());
430+
assert_eq!(a.temporality, temporality);
431+
assert_eq!(a.data_points.len(), 1);
432+
assert_eq!(
433+
a.data_points[0].attributes,
434+
AttributeSet::from(&new_attributes[..])
435+
);
436+
assert_eq!(a.data_points[0].count, 1);
437+
assert_eq!(a.data_points[0].min, Some(3));
438+
assert_eq!(a.data_points[0].max, Some(3));
439+
assert_eq!(a.data_points[0].sum, 3);
440+
assert_eq!(a.data_points[0].zero_count, 0);
441+
assert_eq!(a.data_points[0].zero_threshold, 0.0);
442+
assert_eq!(a.data_points[0].positive_bucket.offset, 1661953);
443+
assert_eq!(a.data_points[0].positive_bucket.counts, vec![1]);
444+
assert_eq!(a.data_points[0].negative_bucket.offset, 0);
445+
assert!(a.data_points[0].negative_bucket.counts.is_empty());
446+
}
447+
}
448+
}

0 commit comments

Comments
 (0)