From 138334fb31f6bc183836a17f7015bb994bfc8f62 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Tue, 28 May 2013 17:36:53 +0200 Subject: [PATCH] Fix handling of negative deltas for non-counter values. --- rules/ast/functions.go | 6 +++--- rules/helpers_test.go | 11 +++++++++-- rules/rules_test.go | 24 ++++++++++++++++++------ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/rules/ast/functions.go b/rules/ast/functions.go index 7fba2b116..f155fa0ba 100644 --- a/rules/ast/functions.go +++ b/rules/ast/functions.go @@ -72,14 +72,14 @@ func timeImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} { // === delta(matrix MatrixNode, isCounter ScalarNode) Vector === func deltaImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} { matrixNode := args[0].(MatrixNode) - isCounter := int(args[1].(ScalarNode).Eval(timestamp, view)) + isCounter := args[1].(ScalarNode).Eval(timestamp, view) > 0 resultVector := Vector{} // If we treat these metrics as counters, we need to fetch all values // in the interval to find breaks in the timeseries' monotonicity. // I.e. if a counter resets, we want to ignore that reset. var matrixValue Matrix - if isCounter > 0 { + if isCounter { matrixValue = matrixNode.Eval(timestamp, view) } else { matrixValue = matrixNode.EvalBoundaries(timestamp, view) @@ -95,7 +95,7 @@ func deltaImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} lastValue := model.SampleValue(0) for _, sample := range samples.Values { currentValue := sample.Value - if currentValue < lastValue { + if isCounter && currentValue < lastValue { counterCorrection += lastValue - currentValue } lastValue = currentValue diff --git a/rules/helpers_test.go b/rules/helpers_test.go index ed8c6676d..9a17df912 100644 --- a/rules/helpers_test.go +++ b/rules/helpers_test.go @@ -145,13 +145,20 @@ var testMatrix = ast.Matrix{ }, Values: getTestValueStream(0, 100, 10, testStartTime), }, - // Counter resets. + // Counter reset in the middle of range. { Metric: model.Metric{ - model.MetricNameLabel: "testcounter", + model.MetricNameLabel: "testcounter_reset_middle", }, Values: append(getTestValueStream(0, 40, 10, testStartTime), getTestValueStream(0, 50, 10, testStartTime.Add(testSampleInterval*5))...), }, + // Counter reset at the end of range. + { + Metric: model.Metric{ + model.MetricNameLabel: "testcounter_reset_end", + }, + Values: append(getTestValueStream(0, 90, 10, testStartTime), getTestValueStream(0, 0, 10, testStartTime.Add(testSampleInterval*10))...), + }, } var testVector = getTestVectorFromTestMatrix(testMatrix) diff --git a/rules/rules_test.go b/rules/rules_test.go index 0d3092adf..d2f9d8b23 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -319,15 +319,27 @@ func TestExpressions(t *testing.T) { fullRanges: 1, intervalRanges: 0, }, { - // Counter resets are ignored by delta() if counter == 1. - expr: "delta(testcounter[50m], 1)", - output: []string{"testcounter{} => 90 @[%v]"}, + // Counter resets in middle of range are ignored by delta() if counter == 1. + expr: "delta(testcounter_reset_middle[50m], 1)", + output: []string{"testcounter_reset_middle{} => 90 @[%v]"}, fullRanges: 1, intervalRanges: 0, }, { - // Counter resets are not ignored by delta() if counter == 0. - expr: "delta(testcounter[50m], 0)", - output: []string{"testcounter{} => 50 @[%v]"}, + // Counter resets in middle of range are not ignored by delta() if counter == 0. + expr: "delta(testcounter_reset_middle[50m], 0)", + output: []string{"testcounter_reset_middle{} => 50 @[%v]"}, + fullRanges: 1, + intervalRanges: 0, + }, { + // Counter resets at end of range are ignored by delta() if counter == 1. + expr: "delta(testcounter_reset_end[5m], 1)", + output: []string{"testcounter_reset_end{} => 0 @[%v]"}, + fullRanges: 1, + intervalRanges: 0, + }, { + // Counter resets at end of range are not ignored by delta() if counter == 0. + expr: "delta(testcounter_reset_end[5m], 0)", + output: []string{"testcounter_reset_end{} => -90 @[%v]"}, fullRanges: 1, intervalRanges: 0, }, {