fix(promql): report 0 from ts_of_last_over_time for negative timestamps

Prometheus 3.15 takes the max of the last float timestamp and the
histogram one, which defaults to 0 without histograms.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
This commit is contained in:
Dennis Zhuang
2026-10-17 23:07:11 +08:00
parent a56faf76b9
commit 09cb32a3e3
2 changed files with 30 additions and 3 deletions
+4 -3
View File
@@ -125,10 +125,11 @@ impl RangeFunction {
Self::TsOfFirstOverTime => {
Box::new(move |window| Some(seconds(window.timestamps[0] - offset_ms)))
}
// Prometheus takes the max with the histogram timestamp, 0 when there is none, so a
// negative timestamp reports 0.
Self::TsOfLastOverTime => Box::new(move |window| {
Some(seconds(
window.timestamps[window.timestamps.len() - 1] - offset_ms,
))
let last = window.timestamps[window.timestamps.len() - 1] - offset_ms;
Some(seconds(last.max(0)))
}),
Self::TsOfMinOverTime => Box::new(move |window| {
Some(seconds(timestamp_of_extremum(&window, false) - offset_ms))
+26
View File
@@ -1026,3 +1026,29 @@ fn waiting_for_a_point_drops_samples_behind_its_window() {
let last = chunk(&[(100_000, vec![Some(1.0)])], 1, 0, true);
assert!(evaluator.push(&last).unwrap().is_some());
}
/// Prometheus 3.15 reports `ts_of_last_over_time` as the max of the last float timestamp and
/// a histogram timestamp that defaults to 0, so a window of negative timestamps reports 0;
/// `ts_of_first_over_time` takes the min and keeps them.
#[test]
fn ts_of_last_over_time_reports_zero_for_negative_timestamps() {
let window = RangeWindow {
range_ms: 2_000,
offset_ms: 0,
anchor_ms: None,
};
let rows: Vec<Row> = vec![(-1_000, vec![Some(7.0)])];
for (function, expected) in [
(RangeFunction::TsOfLastOverTime, 0.0),
(RangeFunction::TsOfFirstOverTime, -1.0),
] {
let mut evaluator =
RangeEvaluator::try_new(&raw_schema(1), grid(0, 1_000, 1), window, function).unwrap();
let series = evaluator.push(&chunk(&rows, 1, 0, true)).unwrap().unwrap();
assert_series_eq(
Some(&series),
&vec![vec![Some(expected)]],
&output_metric(function, 0),
);
}
}