From 0ce5e7fe6d5a0bf41324468b7ae673d2682821ff Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Mon, 8 Aug 2016 10:02:58 +0200 Subject: [PATCH 1/3] move legacy test for delta function --- promql/testdata/functions.test | 9 +++++++++ promql/testdata/legacy.test | 5 ----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/promql/testdata/functions.test b/promql/testdata/functions.test index 58b1ee5720..273585e1e6 100644 --- a/promql/testdata/functions.test +++ b/promql/testdata/functions.test @@ -85,6 +85,15 @@ eval instant at 30m irate(http_requests[50m]) clear +# Tests for delta(). +load 5m + http_requests{path="/foo"} 0 50 100 150 200 + +eval instant at 20m delta(http_requests[20m]) + {path="/foo"} 200 + +clear + # Tests for deriv() and predict_linear(). load 5m testcounter_reset_middle 0+10x4 0+10x5 diff --git a/promql/testdata/legacy.test b/promql/testdata/legacy.test index 6da0281a7b..1556485f8c 100644 --- a/promql/testdata/legacy.test +++ b/promql/testdata/legacy.test @@ -91,11 +91,6 @@ eval instant at 50m x{y="testvalue"} x{y="testvalue"} 100 -# Deltas should be adjusted for target interval vs. samples under target interval. -eval instant at 50m delta(http_requests{group="canary", instance="1", job="app-server"}[18m]) - {group="canary", instance="1", job="app-server"} 288 - - # Rates should calculate per-second rates. eval instant at 50m rate(http_requests{group="canary", instance="1", job="app-server"}[50m]) {group="canary", instance="1", job="app-server"} 0.26666666666666666 From dbf83666bb135b1ee236aa3120e470a235732c4a Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Mon, 8 Aug 2016 10:40:50 +0200 Subject: [PATCH 2/3] add idelta function similar to the irate function the idelta function calculates the delta function with the last two values --- promql/functions.go | 37 ++++++++++++++++++++++++++++++++++ promql/testdata/functions.test | 13 ++++++++++++ 2 files changed, 50 insertions(+) diff --git a/promql/functions.go b/promql/functions.go index ff54e24d7a..20a76b9e7f 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -183,6 +183,37 @@ func funcIrate(ev *evaluator, args Expressions) model.Value { return resultVector } +// === idelta(node model.ValMatric) Vector === +func funcIdelta(ev *evaluator, args Expressions) model.Value { + resultVector := vector{} + for _, samples := range ev.evalMatrix(args[0]) { + // No sense in trying to compute a rate without at least two points. Drop + // this vector element. + if len(samples.Values) < 2 { + continue + } + + lastSample := samples.Values[len(samples.Values)-1] + previousSample := samples.Values[len(samples.Values)-2] + resultValue := lastSample.Value - previousSample.Value + + sampledInterval := lastSample.Timestamp.Sub(previousSample.Timestamp) + if sampledInterval == 0 { + // Avoid dividing by 0. + continue + } + + resultSample := &sample{ + Metric: samples.Metric, + Value: resultValue, + Timestamp: ev.Timestamp, + } + resultSample.Metric.Del(model.MetricNameLabel) + resultVector = append(resultVector, resultSample) + } + return resultVector +} + // Calculate the trend value at the given index i in raw data d. // This is somewhat analogous to the slope of the trend at the given index. // The argument "s" is the set of computed smoothed values. @@ -956,6 +987,12 @@ var functions = map[string]*Function{ ReturnType: model.ValVector, Call: funcIrate, }, + "idelta": { + Name: "idelta", + ArgTypes: []model.ValueType{model.ValMatrix}, + ReturnType: model.ValVector, + Call: funcIdelta, + }, "label_replace": { Name: "label_replace", ArgTypes: []model.ValueType{model.ValVector, model.ValString, model.ValString, model.ValString, model.ValString}, diff --git a/promql/testdata/functions.test b/promql/testdata/functions.test index 273585e1e6..cbc789fd55 100644 --- a/promql/testdata/functions.test +++ b/promql/testdata/functions.test @@ -88,9 +88,22 @@ clear # Tests for delta(). load 5m http_requests{path="/foo"} 0 50 100 150 200 + http_requests{path="/bar"} 200 150 100 50 0 eval instant at 20m delta(http_requests[20m]) {path="/foo"} 200 + {path="/bar"} -200 + +clear + +# Tests for idelta(). +load 5m + http_requests{path="/foo"} 0 50 100 150 + http_requests{path="/bar"} 0 50 100 50 + +eval instant at 20m idelta(http_requests[20m]) + {path="/foo"} 50 + {path="/bar"} -50 clear From f02df4138c24cbadee7b965776955dc44f9e1fa0 Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Mon, 8 Aug 2016 10:52:00 +0200 Subject: [PATCH 3/3] refactor duplication of irate and idelta functions implementations --- promql/functions.go | 47 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/promql/functions.go b/promql/functions.go index 20a76b9e7f..251838607e 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -145,8 +145,17 @@ func funcIncrease(ev *evaluator, args Expressions) model.Value { // === irate(node model.ValMatrix) Vector === func funcIrate(ev *evaluator, args Expressions) model.Value { + return instantValue(ev, args[0], true) +} + +// === idelta(node model.ValMatric) Vector === +func funcIdelta(ev *evaluator, args Expressions) model.Value { + return instantValue(ev, args[0], false) +} + +func instantValue(ev *evaluator, arg Expr, isRate bool) model.Value { resultVector := vector{} - for _, samples := range ev.evalMatrix(args[0]) { + for _, samples := range ev.evalMatrix(arg) { // No sense in trying to compute a rate without at least two points. Drop // this vector element. if len(samples.Values) < 2 { @@ -157,7 +166,7 @@ func funcIrate(ev *evaluator, args Expressions) model.Value { previousSample := samples.Values[len(samples.Values)-2] var resultValue model.SampleValue - if lastSample.Value < previousSample.Value { + if isRate && lastSample.Value < previousSample.Value { // Counter reset. resultValue = lastSample.Value } else { @@ -169,38 +178,10 @@ func funcIrate(ev *evaluator, args Expressions) model.Value { // Avoid dividing by 0. continue } - // Convert to per-second. - resultValue /= model.SampleValue(sampledInterval.Seconds()) - resultSample := &sample{ - Metric: samples.Metric, - Value: resultValue, - Timestamp: ev.Timestamp, - } - resultSample.Metric.Del(model.MetricNameLabel) - resultVector = append(resultVector, resultSample) - } - return resultVector -} - -// === idelta(node model.ValMatric) Vector === -func funcIdelta(ev *evaluator, args Expressions) model.Value { - resultVector := vector{} - for _, samples := range ev.evalMatrix(args[0]) { - // No sense in trying to compute a rate without at least two points. Drop - // this vector element. - if len(samples.Values) < 2 { - continue - } - - lastSample := samples.Values[len(samples.Values)-1] - previousSample := samples.Values[len(samples.Values)-2] - resultValue := lastSample.Value - previousSample.Value - - sampledInterval := lastSample.Timestamp.Sub(previousSample.Timestamp) - if sampledInterval == 0 { - // Avoid dividing by 0. - continue + if isRate { + // Convert to per-second. + resultValue /= model.SampleValue(sampledInterval.Seconds()) } resultSample := &sample{