promql: Add support for predict_linear(my_timeseries[1h], 7200)
This will give a prediction for the value of my_timeseries in 2 hours, based on the last hour of data.
This commit is contained in:
parent
beae7b6afb
commit
d6a80c2b76
|
@ -474,6 +474,43 @@ func funcDeriv(ev *evaluator, args Expressions) Value {
|
||||||
return resultVector
|
return resultVector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === predict_linear(node ExprMatrix, k ExprScalar) Vector ===
|
||||||
|
func funcPredictLinear(ev *evaluator, args Expressions) Value {
|
||||||
|
vector := funcDeriv(ev, args[0:1]).(Vector)
|
||||||
|
duration := clientmodel.SampleValue(clientmodel.SampleValue(ev.evalFloat(args[1])))
|
||||||
|
|
||||||
|
excludedLabels := map[clientmodel.LabelName]struct{}{
|
||||||
|
clientmodel.MetricNameLabel: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate predicted delta over the duration.
|
||||||
|
signatureToDelta := map[uint64]clientmodel.SampleValue{}
|
||||||
|
for _, el := range vector {
|
||||||
|
signature := clientmodel.SignatureWithoutLabels(el.Metric.Metric, excludedLabels)
|
||||||
|
signatureToDelta[signature] = el.Value * duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// add predicted delta to last value.
|
||||||
|
matrixBounds := ev.evalMatrixBounds(args[0])
|
||||||
|
outVec := make(Vector, 0, len(signatureToDelta))
|
||||||
|
for _, samples := range matrixBounds {
|
||||||
|
if len(samples.Values) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
signature := clientmodel.SignatureWithoutLabels(samples.Metric.Metric, excludedLabels)
|
||||||
|
delta, ok := signatureToDelta[signature]
|
||||||
|
if ok {
|
||||||
|
samples.Metric.Delete(clientmodel.MetricNameLabel)
|
||||||
|
outVec = append(outVec, &Sample{
|
||||||
|
Metric: samples.Metric,
|
||||||
|
Value: delta + samples.Values[1].Value,
|
||||||
|
Timestamp: ev.Timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outVec
|
||||||
|
}
|
||||||
|
|
||||||
// === histogram_quantile(k ExprScalar, vector ExprVector) Vector ===
|
// === histogram_quantile(k ExprScalar, vector ExprVector) Vector ===
|
||||||
func funcHistogramQuantile(ev *evaluator, args Expressions) Value {
|
func funcHistogramQuantile(ev *evaluator, args Expressions) Value {
|
||||||
q := clientmodel.SampleValue(ev.evalFloat(args[0]))
|
q := clientmodel.SampleValue(ev.evalFloat(args[0]))
|
||||||
|
@ -688,6 +725,12 @@ var functions = map[string]*Function{
|
||||||
ReturnType: ExprVector,
|
ReturnType: ExprVector,
|
||||||
Call: funcMinOverTime,
|
Call: funcMinOverTime,
|
||||||
},
|
},
|
||||||
|
"predict_linear": {
|
||||||
|
Name: "predict_linear",
|
||||||
|
ArgTypes: []ExprType{ExprMatrix, ExprScalar},
|
||||||
|
ReturnType: ExprVector,
|
||||||
|
Call: funcPredictLinear,
|
||||||
|
},
|
||||||
"rate": {
|
"rate": {
|
||||||
Name: "rate",
|
Name: "rate",
|
||||||
ArgTypes: []ExprType{ExprMatrix},
|
ArgTypes: []ExprType{ExprMatrix},
|
||||||
|
|
|
@ -62,3 +62,33 @@ load 5m
|
||||||
eval instant at 50m increase(http_requests[50m])
|
eval instant at 50m increase(http_requests[50m])
|
||||||
{path="/foo"} 100
|
{path="/foo"} 100
|
||||||
{path="/bar"} 90
|
{path="/bar"} 90
|
||||||
|
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
# Tests for deriv() and predict_linear().
|
||||||
|
load 5m
|
||||||
|
testcounter_reset_middle 0+10x4 0+10x5
|
||||||
|
http_requests{job="app-server", instance="1", group="canary"} 0+80x10
|
||||||
|
|
||||||
|
# Deriv should return the same as rate in simple cases.
|
||||||
|
eval instant at 50m rate(http_requests{group="canary", instance="1", job="app-server"}[60m])
|
||||||
|
{group="canary", instance="1", job="app-server"} 0.26666666666666666
|
||||||
|
|
||||||
|
eval instant at 50m deriv(http_requests{group="canary", instance="1", job="app-server"}[60m])
|
||||||
|
{group="canary", instance="1", job="app-server"} 0.26666666666666666
|
||||||
|
|
||||||
|
# Deriv should return correct result.
|
||||||
|
eval instant at 50m deriv(testcounter_reset_middle[100m])
|
||||||
|
{} 0.010606060606060607
|
||||||
|
|
||||||
|
# Predict_linear should return correct result.
|
||||||
|
eval instant at 50m predict_linear(testcounter_reset_middle[100m], 3600)
|
||||||
|
{} 88.181818181818185200
|
||||||
|
|
||||||
|
# Predict_linear is syntactic sugar around deriv.
|
||||||
|
eval instant at 50m predict_linear(http_requests[50m], 3600) - (http_requests + deriv(http_requests[50m]) * 3600)
|
||||||
|
{group="canary", instance="1", job="app-server"} 0
|
||||||
|
|
||||||
|
eval instant at 50m predict_linear(testcounter_reset_middle[100m], 3600) - (testcounter_reset_middle + deriv(testcounter_reset_middle[100m]) * 3600)
|
||||||
|
{} 0
|
||||||
|
|
|
@ -238,10 +238,6 @@ eval instant at 50m delta(http_requests{group="canary", instance="1", job="app-s
|
||||||
eval instant at 50m rate(http_requests{group="canary", instance="1", job="app-server"}[60m])
|
eval instant at 50m rate(http_requests{group="canary", instance="1", job="app-server"}[60m])
|
||||||
{group="canary", instance="1", job="app-server"} 0.26666666666666666
|
{group="canary", instance="1", job="app-server"} 0.26666666666666666
|
||||||
|
|
||||||
# Deriv should return the same as rate in simple cases.
|
|
||||||
eval instant at 50m deriv(http_requests{group="canary", instance="1", job="app-server"}[60m])
|
|
||||||
{group="canary", instance="1", job="app-server"} 0.26666666666666666
|
|
||||||
|
|
||||||
# Counter resets at in the middle of range are handled correctly by rate().
|
# Counter resets at in the middle of range are handled correctly by rate().
|
||||||
eval instant at 50m rate(testcounter_reset_middle[60m])
|
eval instant at 50m rate(testcounter_reset_middle[60m])
|
||||||
{} 0.03
|
{} 0.03
|
||||||
|
@ -251,10 +247,6 @@ eval instant at 50m rate(testcounter_reset_middle[60m])
|
||||||
eval instant at 50m rate(testcounter_reset_end[5m])
|
eval instant at 50m rate(testcounter_reset_end[5m])
|
||||||
{} 0
|
{} 0
|
||||||
|
|
||||||
# Deriv should return correct result.
|
|
||||||
eval instant at 50m deriv(testcounter_reset_middle[100m])
|
|
||||||
{} 0.010606060606060607
|
|
||||||
|
|
||||||
# count_scalar for a non-empty vector should return scalar element count.
|
# count_scalar for a non-empty vector should return scalar element count.
|
||||||
eval instant at 50m count_scalar(http_requests)
|
eval instant at 50m count_scalar(http_requests)
|
||||||
8
|
8
|
||||||
|
|
Loading…
Reference in New Issue