diff --git a/changelog.d/25621_datadog_metrics_sort.fix.md b/changelog.d/25621_datadog_metrics_sort.fix.md new file mode 100644 index 0000000000000..2655c8ad88b03 --- /dev/null +++ b/changelog.d/25621_datadog_metrics_sort.fix.md @@ -0,0 +1,3 @@ +Fixed a bug in the `datadog_metrics` sink where the metric type name was compared against itself (instead of the peer metric) when sorting metrics before encoding. The sort key is `(type_name, metric_name, timestamp)`, but the type comparison was a no-op, making `metric_name` the effective primary key. The fix restores the intended ordering. + +authors: gwenaskell diff --git a/src/sinks/datadog/metrics/sink.rs b/src/sinks/datadog/metrics/sink.rs index a366cc81150c8..89a64f18920bb 100644 --- a/src/sinks/datadog/metrics/sink.rs +++ b/src/sinks/datadog/metrics/sink.rs @@ -217,7 +217,7 @@ fn sort_and_collapse_counters_by_series_and_timestamp(mut metrics: Vec) a.timestamp().map(|dt| dt.timestamp()).unwrap_or(now_ts), ) .cmp(&( - a.value().as_name(), + b.value().as_name(), b.series(), b.timestamp().map(|dt| dt.timestamp()).unwrap_or(now_ts), )) @@ -393,6 +393,24 @@ mod tests { assert_eq!(expected, actual); } + #[test] + fn sort_metric_type_is_primary_sort_key() { + // The sort key is (type_name, series, timestamp). "counter" < "gauge" alphabetically, + // so a counter must always precede a gauge regardless of series name. + let input = vec![ + create_gauge("aaa", 1.0), + create_counter("zzz", 1.0), + create_counter("aaa", 1.0), + ]; + let expected = vec![ + create_counter("aaa", 1.0), + create_counter("zzz", 1.0), + create_gauge("aaa", 1.0), + ]; + let actual = sort_and_collapse_counters_by_series_and_timestamp(input); + assert_eq!(expected, actual); + } + #[test] fn collapse_identical_metrics_multiple_timestamps() { let ts_1 = Utc::now() - Duration::from_secs(5);