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:
Brian Brazil 2015-07-28 12:30:57 +01:00 committed by Brian Brazil
parent beae7b6afb
commit d6a80c2b76
3 changed files with 73 additions and 8 deletions

View File

@ -474,6 +474,43 @@ func funcDeriv(ev *evaluator, args Expressions) Value {
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 ===
func funcHistogramQuantile(ev *evaluator, args Expressions) Value {
q := clientmodel.SampleValue(ev.evalFloat(args[0]))
@ -688,6 +725,12 @@ var functions = map[string]*Function{
ReturnType: ExprVector,
Call: funcMinOverTime,
},
"predict_linear": {
Name: "predict_linear",
ArgTypes: []ExprType{ExprMatrix, ExprScalar},
ReturnType: ExprVector,
Call: funcPredictLinear,
},
"rate": {
Name: "rate",
ArgTypes: []ExprType{ExprMatrix},

View File

@ -62,3 +62,33 @@ load 5m
eval instant at 50m increase(http_requests[50m])
{path="/foo"} 100
{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

View File

@ -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])
{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().
eval instant at 50m rate(testcounter_reset_middle[60m])
{} 0.03
@ -251,10 +247,6 @@ eval instant at 50m rate(testcounter_reset_middle[60m])
eval instant at 50m rate(testcounter_reset_end[5m])
{} 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.
eval instant at 50m count_scalar(http_requests)
8