mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-05 13:47:10 +02:00
promql: add ts_of_(max,min,last)_over_time functions
This commit adds the ts_of_(max,min,last)_over_time functions behind the experimental feature flag. Signed-off-by: Michael Hoffmann <mhoffmann@cloudflare.com>
This commit is contained in:
parent
f8508ccafa
commit
a5fa9431d8
@ -847,6 +847,12 @@ additional functions are available:
|
||||
|
||||
* `mad_over_time(range-vector)`: the median absolute deviation of all float
|
||||
samples in the specified interval.
|
||||
* `ts_of_min_over_time(range-vector)`: the timestamp of the last float sample
|
||||
that has the minimum value of all float samples in the specified interval.
|
||||
* `ts_of_max_over_time(range-vector)`: the timestamp of the last float sample
|
||||
that has the maximum value of all float samples in the specified interval.
|
||||
* `ts_of_last_over_time(range-vector)`: the timestamp of last sample in the
|
||||
specified interval.
|
||||
|
||||
Note that all values in the specified interval have the same weight in the
|
||||
aggregation even if the values are not equally spaced throughout the interval.
|
||||
|
@ -784,8 +784,42 @@ func funcMadOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||
}), annos
|
||||
}
|
||||
|
||||
// === ts_of_last_over_time(Matrix parser.ValueTypeMatrix) (Vector, Notes) ===
|
||||
func funcTsOfLastOverTime(vals []parser.Value, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
|
||||
el := vals[0].(Matrix)[0]
|
||||
|
||||
var tf int64
|
||||
if len(el.Floats) > 0 {
|
||||
tf = el.Floats[len(el.Floats)-1].T
|
||||
}
|
||||
|
||||
var th int64
|
||||
if len(el.Histograms) > 0 {
|
||||
th = el.Floats[len(el.Floats)-1].T
|
||||
}
|
||||
|
||||
return append(enh.Out, Sample{
|
||||
Metric: el.Metric,
|
||||
F: float64(max(tf, th)) / 1000,
|
||||
}), nil
|
||||
}
|
||||
|
||||
// === ts_of_max_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
|
||||
func funcTsOfMaxOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
|
||||
return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
|
||||
return (cur >= maxVal) || math.IsNaN(maxVal)
|
||||
}, true)
|
||||
}
|
||||
|
||||
// === ts_of_min_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
|
||||
func funcTsOfMinOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
|
||||
return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
|
||||
return (cur <= maxVal) || math.IsNaN(maxVal)
|
||||
}, true)
|
||||
}
|
||||
|
||||
// compareOverTime is a helper used by funcMaxOverTime and funcMinOverTime.
|
||||
func compareOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper, compareFn func(float64, float64) bool) (Vector, annotations.Annotations) {
|
||||
func compareOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper, compareFn func(float64, float64) bool, returnTimestamp bool) (Vector, annotations.Annotations) {
|
||||
samples := vals[0].(Matrix)[0]
|
||||
var annos annotations.Annotations
|
||||
if len(samples.Floats) == 0 {
|
||||
@ -797,11 +831,16 @@ func compareOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||
}
|
||||
return aggrOverTime(vals, enh, func(s Series) float64 {
|
||||
maxVal := s.Floats[0].F
|
||||
tsOfMax := s.Floats[0].T
|
||||
for _, f := range s.Floats {
|
||||
if compareFn(f.F, maxVal) {
|
||||
maxVal = f.F
|
||||
tsOfMax = f.T
|
||||
}
|
||||
}
|
||||
if returnTimestamp {
|
||||
return float64(tsOfMax) / 1000
|
||||
}
|
||||
return maxVal
|
||||
}), annos
|
||||
}
|
||||
@ -810,14 +849,14 @@ func compareOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||
func funcMaxOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
|
||||
return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
|
||||
return (cur > maxVal) || math.IsNaN(maxVal)
|
||||
})
|
||||
}, false)
|
||||
}
|
||||
|
||||
// === min_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
|
||||
func funcMinOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
|
||||
return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
|
||||
return (cur < maxVal) || math.IsNaN(maxVal)
|
||||
})
|
||||
}, false)
|
||||
}
|
||||
|
||||
// === sum_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
|
||||
@ -1723,6 +1762,9 @@ var FunctionCalls = map[string]FunctionCall{
|
||||
"mad_over_time": funcMadOverTime,
|
||||
"max_over_time": funcMaxOverTime,
|
||||
"min_over_time": funcMinOverTime,
|
||||
"ts_of_last_over_time": funcTsOfLastOverTime,
|
||||
"ts_of_max_over_time": funcTsOfMaxOverTime,
|
||||
"ts_of_min_over_time": funcTsOfMinOverTime,
|
||||
"minute": funcMinute,
|
||||
"month": funcMonth,
|
||||
"pi": funcPi,
|
||||
|
@ -283,6 +283,24 @@ var Functions = map[string]*Function{
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"ts_of_max_over_time": {
|
||||
Name: "ts_of_max_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
Experimental: true,
|
||||
},
|
||||
"ts_of_min_over_time": {
|
||||
Name: "ts_of_min_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
Experimental: true,
|
||||
},
|
||||
"ts_of_last_over_time": {
|
||||
Name: "ts_of_last_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
Experimental: true,
|
||||
},
|
||||
"minute": {
|
||||
Name: "minute",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
|
22
promql/promqltest/testdata/functions.test
vendored
22
promql/promqltest/testdata/functions.test
vendored
@ -1186,6 +1186,28 @@ eval instant at 70s mad_over_time(metric_histogram{type="only_histogram"}[70s])
|
||||
eval_info instant at 70s mad_over_time(metric_histogram{type="mix"}[70s])
|
||||
{type="mix"} 0
|
||||
|
||||
# Tests for ts_of_max_over_time and ts_of_min_over_time. Using odd scrape interval to test for rounding bugs.
|
||||
clear
|
||||
load 10s53ms
|
||||
metric 1 2 3 0 5 6 2 1 4
|
||||
|
||||
eval instant at 90s ts_of_min_over_time(metric[90s])
|
||||
{} 30.159
|
||||
|
||||
eval instant at 90s ts_of_max_over_time(metric[90s])
|
||||
{} 50.265
|
||||
|
||||
# Tests for ts_of_last_over_time. Using odd load interval to test for rounding bugs.
|
||||
clear
|
||||
load 10s53ms
|
||||
metric 1 2 3 _ _
|
||||
|
||||
eval instant at 90s ts_of_last_over_time(metric[90s])
|
||||
{} 20.106
|
||||
|
||||
eval instant at 95s ts_of_last_over_time(metric[90s])
|
||||
{} 20.106
|
||||
|
||||
# Tests for quantile_over_time
|
||||
clear
|
||||
|
||||
|
@ -347,6 +347,24 @@ export const functionIdentifierTerms = [
|
||||
info: 'Return the minimum value over time for input series',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
label: 'ts_of_max_over_time',
|
||||
detail: 'function',
|
||||
info: 'Return the timestamp of the maximum value over time for input series',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
label: 'ts_of_min_over_time',
|
||||
detail: 'function',
|
||||
info: 'Return the timestamp of the minimum value over time for input series',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
label: 'ts_of_last_over_time',
|
||||
detail: 'function',
|
||||
info: 'Return the timestamp of the last value over time for input series',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
label: 'minute',
|
||||
detail: 'function',
|
||||
|
@ -105,6 +105,21 @@ describe('promql operations', () => {
|
||||
expectedValueType: ValueType.vector,
|
||||
expectedDiag: [] as Diagnostic[],
|
||||
},
|
||||
{
|
||||
expr: 'ts_of_max_over_time(rate(metric_name[5m])[1h:] offset 1m)',
|
||||
expectedValueType: ValueType.vector,
|
||||
expectedDiag: [] as Diagnostic[],
|
||||
},
|
||||
{
|
||||
expr: 'ts_of_min_over_time(rate(metric_name[5m])[1h:] offset 1m)',
|
||||
expectedValueType: ValueType.vector,
|
||||
expectedDiag: [] as Diagnostic[],
|
||||
},
|
||||
{
|
||||
expr: 'ts_of_last_over_time(rate(metric_name[5m])[1h:] offset 1m)',
|
||||
expectedValueType: ValueType.vector,
|
||||
expectedDiag: [] as Diagnostic[],
|
||||
},
|
||||
{
|
||||
expr: 'foo * bar',
|
||||
expectedValueType: ValueType.vector,
|
||||
|
@ -61,6 +61,9 @@ import {
|
||||
MadOverTime,
|
||||
MaxOverTime,
|
||||
MinOverTime,
|
||||
TsOfMaxOverTime,
|
||||
TsOfMinOverTime,
|
||||
TsOfLastOverTime,
|
||||
Minute,
|
||||
Month,
|
||||
Pi,
|
||||
@ -403,6 +406,24 @@ const promqlFunctions: { [key: number]: PromQLFunction } = {
|
||||
variadic: 0,
|
||||
returnType: ValueType.vector,
|
||||
},
|
||||
[TsOfMaxOverTime]: {
|
||||
name: 'ts_of_max_over_time',
|
||||
argTypes: [ValueType.matrix],
|
||||
variadic: 0,
|
||||
returnType: ValueType.vector,
|
||||
},
|
||||
[TsOfMinOverTime]: {
|
||||
name: 'ts_of_min_over_time',
|
||||
argTypes: [ValueType.matrix],
|
||||
variadic: 0,
|
||||
returnType: ValueType.vector,
|
||||
},
|
||||
[TsOfLastOverTime]: {
|
||||
name: 'ts_of_last_over_time',
|
||||
argTypes: [ValueType.matrix],
|
||||
variadic: 0,
|
||||
returnType: ValueType.vector,
|
||||
},
|
||||
[Minute]: {
|
||||
name: 'minute',
|
||||
argTypes: [ValueType.vector],
|
||||
|
@ -156,6 +156,9 @@ FunctionIdentifier {
|
||||
MadOverTime |
|
||||
MaxOverTime |
|
||||
MinOverTime |
|
||||
TsOfMaxOverTime |
|
||||
TsOfMinOverTime |
|
||||
TsOfLastOverTime |
|
||||
Minute |
|
||||
Month |
|
||||
Pi |
|
||||
@ -404,6 +407,9 @@ NumberDurationLiteralInDurationContext {
|
||||
MadOverTime { condFn<"mad_over_time"> }
|
||||
MaxOverTime { condFn<"max_over_time"> }
|
||||
MinOverTime { condFn<"min_over_time"> }
|
||||
TsOfMaxOverTime { condFn<"ts_of_max_over_time"> }
|
||||
TsOfMinOverTime { condFn<"ts_of_min_over_time"> }
|
||||
TsOfLastOverTime { condFn<"ts_of_last_over_time"> }
|
||||
Minute { condFn<"minute"> }
|
||||
Month { condFn<"month"> }
|
||||
Pi { condFn<"pi">}
|
||||
|
Loading…
Reference in New Issue
Block a user