From 4e901d7cc780e1d7dfc414585c51fad5f01be11b Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Wed, 26 Aug 2020 21:13:48 -0700 Subject: [PATCH 01/20] Added the moving movingMin function --- .../graphite/native/builtin_functions_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 6b76608f90..ace67a79a8 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -2474,6 +2474,24 @@ func testMovingMedian(t *testing.T) { []common.TestSeries{expected}, res.Values) } +func TestMovingMin(t *testing.T) { + // create test context + now := time.Now() + engine := NewEngine( + testStorage, + ) + startTime := now.Add(-3 * time.Minute) + endTime := now.Add(-time.Minute) + ctx := common.NewContext(common.ContextOptions{Start: startTime, End: endTime, Engine: engine}) + defer ctx.Close() + + + vals := []float64{1.0, 2.0, 3.0, 4.0, math.NaN()} + expected := common.TestSeries{Name: "foo (avg: 2.500)", Data: vals} + + common.CompareOutputsAndExpected(t, 10000, testMovingAverageStart, expected, res.Values) +} + func TestLegendValue(t *testing.T) { ctx := common.NewTestContext() defer ctx.Close() From f0df4ce2d1ab81420b814b7d8c285ca35dcd7dd9 Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Thu, 27 Aug 2020 09:36:32 -0700 Subject: [PATCH 02/20] worked on moving min --- .../graphite/native/builtin_functions.go | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index e10ba3c856..fb131ccc70 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1632,6 +1632,33 @@ func movingMedian(ctx *common.Context, _ singlePathSpec, windowSize string) (*bi return original, nil } + return &binaryContextShifter{ + ContextShiftFunc: contextShiftingFn, + BinaryTransformer: transformerFn, + }, nil +} + +func movingMin(ctx *common.Context, _ singlePathSpec, windowSize string) (*binaryContextShifter, error) { + interval, err := common.ParseInterval(windowSize) + if err != nil { + return nil, err + } + if interval <= 0 { + return nil, common.ErrInvalidIntervalFormat + } + + contextShiftingFn := func(c *common.Context) *common.Context { + opts := common.NewChildContextOptions() + opts.AdjustTimeRange(0, 0, interval, 0) + childCtx := c.NewChildContext(opts) + return childCtx + } + + bootstrapStartTime, bootstrapEndTime := ctx.StartTime.Add(-interval), ctx.StartTime + + + + return &binaryContextShifter{ ContextShiftFunc: contextShiftingFn, BinaryTransformer: transformerFn, From 8ce6dc3fd7471e08456baf216fa12bc682d8ce9d Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Thu, 27 Aug 2020 16:53:26 -0700 Subject: [PATCH 03/20] more work on the moving min func --- src/query/graphite/common/context.go | 1 + src/query/graphite/common/percentiles.go | 10 ++++++++++ src/query/graphite/native/builtin_functions.go | 7 +------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/query/graphite/common/context.go b/src/query/graphite/common/context.go index 6e4d5ba09a..9a873b62cb 100644 --- a/src/query/graphite/common/context.go +++ b/src/query/graphite/common/context.go @@ -68,6 +68,7 @@ type Context struct { contextBase } + // ContextOptions provides the options to create the context with type ContextOptions struct { Start time.Time diff --git a/src/query/graphite/common/percentiles.go b/src/query/graphite/common/percentiles.go index 1a526fefde..e5ef611a71 100644 --- a/src/query/graphite/common/percentiles.go +++ b/src/query/graphite/common/percentiles.go @@ -71,6 +71,16 @@ func SafeSort(input []float64) int { return nans } +func SafeSum(input []float64) float64 { + sum := 0.0 + for _, v := range input { + if !math.IsNaN(v) { + sum += v + } + } + return sum +} + // GetPercentile computes the percentile cut off for an array of floats func GetPercentile(input []float64, percentile float64, interpolate bool) float64 { nans := SafeSort(input) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 221369a922..0c11ee774c 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1636,12 +1636,7 @@ func movingMedian(ctx *common.Context, _ singlePathSpec, windowSize string) (*bi window[idx] = bootstrap.ValueAt(j) } - nans := common.SafeSort(window) - if nans < windowPoints { - index := (windowPoints - nans) / 2 - median := window[nans+index] - vals.SetValueAt(i, median) - } + vals.SetValueAt(i, common.SafeSum(window)) } name := fmt.Sprintf("movingMedian(%s,%q)", series.Name(), windowSize) newSeries := ts.NewSeries(ctx, name, series.StartTime(), vals) From cf9288f774c37a39e18494596884215095434b9e Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Fri, 28 Aug 2020 03:54:12 -0700 Subject: [PATCH 04/20] updated movingMedian --- .../graphite/native/builtin_functions.go | 62 ++++++++++++++++++- .../graphite/native/builtin_functions_test.go | 5 ++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 0c11ee774c..f309c5ba47 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1609,6 +1609,7 @@ func movingMedian(ctx *common.Context, _ singlePathSpec, windowSize string) (*bi } results := make([]*ts.Series, 0, original.Len()) + for i, bootstrap := range bootstrapList.Values { series := original.Values[i] windowPoints := int(interval / (time.Duration(series.MillisPerStep()) * time.Millisecond)) @@ -1636,7 +1637,12 @@ func movingMedian(ctx *common.Context, _ singlePathSpec, windowSize string) (*bi window[idx] = bootstrap.ValueAt(j) } - vals.SetValueAt(i, common.SafeSum(window)) + nans := common.SafeSort(window) + if nans < windowPoints { + index := (windowPoints - nans) / 2 + median := window[nans+index] + vals.SetValueAt(i, median) + } } name := fmt.Sprintf("movingMedian(%s,%q)", series.Name(), windowSize) newSeries := ts.NewSeries(ctx, name, series.StartTime(), vals) @@ -1653,11 +1659,16 @@ func movingMedian(ctx *common.Context, _ singlePathSpec, windowSize string) (*bi }, nil } -func movingMin(ctx *common.Context, _ singlePathSpec, windowSize string) (*binaryContextShifter, error) { +// movingSum takes one metric or a wildcard seriesList followed by a a quoted string +// with a length of time like '1hour' or '5min'. Graphs the sum of the preceding +// datapoints for each point on the graph. All previous datapoints are set to None at +// the beginning of the graph. +func movingSum(ctx *common.Context, _ singlePathSpec, windowSize string) (*binaryContextShifter, error) { interval, err := common.ParseInterval(windowSize) if err != nil { return nil, err } + if interval <= 0 { return nil, common.ErrInvalidIntervalFormat } @@ -1670,9 +1681,53 @@ func movingMin(ctx *common.Context, _ singlePathSpec, windowSize string) (*binar } bootstrapStartTime, bootstrapEndTime := ctx.StartTime.Add(-interval), ctx.StartTime - + transformerFn := func(bootstrapped, original ts.SeriesList) (ts.SeriesList, error) { + bootstrapList, err := combineBootstrapWithOriginal(ctx, + bootstrapStartTime, bootstrapEndTime, + bootstrapped, singlePathSpec(original)) + if err != nil { + return ts.NewSeriesList(), err + } + + results := make([]*ts.Series, 0, original.Len()) + + for i, bootstrap := range bootstrapList.Values { + series := original.Values[i] + windowPoints := int(interval / (time.Duration(series.MillisPerStep()) * time.Millisecond)) + if windowPoints <= 0 { + err := errors.NewInvalidParamsError(fmt.Errorf( + "non positive window points, windowSize=%s, stepSize=%d", + windowSize, series.MillisPerStep())) + return ts.NewSeriesList(), err + } + window := make([]float64, windowPoints) + util.Memset(window, math.NaN()) + numSteps := series.Len() + offset := bootstrap.Len() - numSteps + vals := ts.NewValues(ctx, series.MillisPerStep(), numSteps) + for i := 0; i < numSteps; i++ { + for j := i + offset - windowPoints; j < i+offset; j++ { + if j < 0 || j >= bootstrap.Len() { + continue + } + + idx := j - i - offset + windowPoints + if idx < 0 || idx > len(window)-1 { + continue + } + window[idx] = bootstrap.ValueAt(j) + } + vals.SetValueAt(i, common.SafeSum(window)) + } + name := fmt.Sprintf("movingMedian(%s,%q)", series.Name(), windowSize) + newSeries := ts.NewSeries(ctx, name, series.StartTime(), vals) + results = append(results, newSeries) + } + original.Values = results + return original, nil + } return &binaryContextShifter{ ContextShiftFunc: contextShiftingFn, @@ -1680,6 +1735,7 @@ func movingMin(ctx *common.Context, _ singlePathSpec, windowSize string) (*binar }, nil } + // legendValue takes one metric or a wildcard seriesList and a string in quotes. // Appends a value to the metric name in the legend. Currently one or several of: // "last", "avg", "total", "min", "max". diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 6a68bf59be..4d40e712a5 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -646,7 +646,10 @@ func TestMovingAverageSuccess(t *testing.T) { values := []float64{12.0, 19.0, -10.0, math.NaN(), 10.0} bootstrap := []float64{3.0, 4.0, 5.0} expected := []float64{4.0, 7.0, 12.0, 7.0, 4.5} + expectedMovingSum := []float64{4.0, 7.0, 12.0, 7.0, 4.5} + testMovingAverage(t, "movingAverage(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,\"30s\")", values, bootstrap, expected) + testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingSum(foo.bar.baz,\"30s\")", values, bootstrap, expectedMovingSum) testMovingAverage(t, "movingAverage(foo.bar.baz, 3)", "movingAverage(foo.bar.baz,3)", values, bootstrap, expected) testMovingAverage(t, "movingAverage(foo.bar.baz, 3)", "movingAverage(foo.bar.baz,3)", nil, nil, nil) @@ -2453,6 +2456,8 @@ func TestChanged(t *testing.T) { expected, results.Values) } + + func TestMovingMedian(t *testing.T) { ctrl := xgomock.NewController(t) defer ctrl.Finish() From 1ebe6291aa10f613102830fcc554d898a1f039dc Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Fri, 28 Aug 2020 03:55:39 -0700 Subject: [PATCH 05/20] Apply suggestions from code review --- src/query/graphite/common/context.go | 1 - src/query/graphite/native/builtin_functions.go | 1 - src/query/graphite/native/builtin_functions_test.go | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/query/graphite/common/context.go b/src/query/graphite/common/context.go index 9a873b62cb..6e4d5ba09a 100644 --- a/src/query/graphite/common/context.go +++ b/src/query/graphite/common/context.go @@ -68,7 +68,6 @@ type Context struct { contextBase } - // ContextOptions provides the options to create the context with type ContextOptions struct { Start time.Time diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index f309c5ba47..a5cda55041 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1609,7 +1609,6 @@ func movingMedian(ctx *common.Context, _ singlePathSpec, windowSize string) (*bi } results := make([]*ts.Series, 0, original.Len()) - for i, bootstrap := range bootstrapList.Values { series := original.Values[i] windowPoints := int(interval / (time.Duration(series.MillisPerStep()) * time.Millisecond)) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 4d40e712a5..0a0c2c65a0 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -2456,8 +2456,6 @@ func TestChanged(t *testing.T) { expected, results.Values) } - - func TestMovingMedian(t *testing.T) { ctrl := xgomock.NewController(t) defer ctrl.Finish() From ebaafce11c0e294c2f0a85f95ca02b6c2a6f3aca Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Fri, 28 Aug 2020 04:08:16 -0700 Subject: [PATCH 06/20] testMovingFunction --- src/query/graphite/native/builtin_functions.go | 3 ++- src/query/graphite/native/builtin_functions_test.go | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index a5cda55041..db4af512f0 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1719,7 +1719,7 @@ func movingSum(ctx *common.Context, _ singlePathSpec, windowSize string) (*binar } vals.SetValueAt(i, common.SafeSum(window)) } - name := fmt.Sprintf("movingMedian(%s,%q)", series.Name(), windowSize) + name := fmt.Sprintf("movingSum(%s,%q)", series.Name(), windowSize) newSeries := ts.NewSeries(ctx, name, series.StartTime(), vals) results = append(results, newSeries) } @@ -1983,6 +1983,7 @@ func init() { MustRegisterFunction(mostDeviant) MustRegisterFunction(movingAverage) MustRegisterFunction(movingMedian) + MustRegisterFunction(movingSum) MustRegisterFunction(multiplySeries) MustRegisterFunction(nonNegativeDerivative).WithDefaultParams(map[uint8]interface{}{ 2: math.NaN(), // maxValue diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 0a0c2c65a0..67044b2e4e 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -646,7 +646,7 @@ func TestMovingAverageSuccess(t *testing.T) { values := []float64{12.0, 19.0, -10.0, math.NaN(), 10.0} bootstrap := []float64{3.0, 4.0, 5.0} expected := []float64{4.0, 7.0, 12.0, 7.0, 4.5} - expectedMovingSum := []float64{4.0, 7.0, 12.0, 7.0, 4.5} + expectedMovingSum := []float64{12.0, 21.0, 36.0, 21.0, 9.0} testMovingAverage(t, "movingAverage(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,\"30s\")", values, bootstrap, expected) testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingSum(foo.bar.baz,\"30s\")", values, bootstrap, expectedMovingSum) @@ -2550,7 +2550,7 @@ func TestMovingMedianInvalidLimits(t *testing.T) { func TestMovingMismatchedLimits(t *testing.T) { // NB: this tests the behavior when query limits do not snap exactly to data // points. When limits do not snap exactly, the first point should be omitted. - for _, fn := range []string{"movingAverage", "movingMedian"} { + for _, fn := range []string{"movingAverage", "movingMedian", "movingSum"} { for i := time.Duration(0); i < time.Minute; i += time.Second { testMovingAverageInvalidLimits(t, fn, i) } @@ -2963,6 +2963,7 @@ func TestFunctionsRegistered(t *testing.T) { "mostDeviant", "movingAverage", "movingMedian", + "movingSum", "multiplySeries", "nonNegativeDerivative", "nPercentile", From 2a0643c19bc17c6c815b4cee6093a973973b73ba Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Fri, 28 Aug 2020 04:42:50 -0700 Subject: [PATCH 07/20] wrote test movingSum function --- .../graphite/native/builtin_functions_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 67044b2e4e..c934c344f3 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -688,6 +688,23 @@ func TestMovingAverageError(t *testing.T) { testMovingAverageError(t, "movingAverage(foo.bar.baz, 0)") } +func TestMovingSumSuccess(t *testing.T) { + values := []float64{12.0, 19.0, -10.0, math.NaN(), 10.0} + bootstrap := []float64{3.0, 4.0, 5.0} + expected := []float64{12.0, 21.0, 36.0, 21.0, 9.0} // (3+4+5), (4+5+12), (5+12+19), (12+19-10), (19-10+Nan) + + testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,\"30s\")", values, bootstrap, expected) + testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,3)", nil, nil, nil) + + bootstrapEntireSeries := []float64{3.0, 4.0, 5.0, 12.0, 19.0, -10.0, math.NaN(), 10.0} + testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,\"30s\")", values, bootstrapEntireSeries, expected) +} + +func TestMovingSumError(t *testing.T) { + testMovingAverageError(t, "movingSum(foo.bar.baz, '-30s')") + testMovingAverageError(t, "movingSum(foo.bar.baz, 0)") +} + func TestIsNonNull(t *testing.T) { ctx := common.NewTestContext() defer ctx.Close() From 12a47a78da168f54b8f571f73da00139927942ad Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Thu, 3 Sep 2020 20:50:55 -0400 Subject: [PATCH 08/20] Apply suggestions from code review --- src/query/graphite/common/percentiles.go | 10 --- .../graphite/native/builtin_functions.go | 78 ------------------- 2 files changed, 88 deletions(-) diff --git a/src/query/graphite/common/percentiles.go b/src/query/graphite/common/percentiles.go index e5ef611a71..1a526fefde 100644 --- a/src/query/graphite/common/percentiles.go +++ b/src/query/graphite/common/percentiles.go @@ -71,16 +71,6 @@ func SafeSort(input []float64) int { return nans } -func SafeSum(input []float64) float64 { - sum := 0.0 - for _, v := range input { - if !math.IsNaN(v) { - sum += v - } - } - return sum -} - // GetPercentile computes the percentile cut off for an array of floats func GetPercentile(input []float64, percentile float64, interpolate bool) float64 { nans := SafeSort(input) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index b66a99ec86..a8541e7c0f 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1671,83 +1671,6 @@ func movingMedian(ctx *common.Context, _ singlePathSpec, windowSize string) (*bi }, nil } -// movingSum takes one metric or a wildcard seriesList followed by a a quoted string -// with a length of time like '1hour' or '5min'. Graphs the sum of the preceding -// datapoints for each point on the graph. All previous datapoints are set to None at -// the beginning of the graph. -func movingSum(ctx *common.Context, _ singlePathSpec, windowSize string) (*binaryContextShifter, error) { - interval, err := common.ParseInterval(windowSize) - if err != nil { - return nil, err - } - - if interval <= 0 { - return nil, common.ErrInvalidIntervalFormat - } - - contextShiftingFn := func(c *common.Context) *common.Context { - opts := common.NewChildContextOptions() - opts.AdjustTimeRange(0, 0, interval, 0) - childCtx := c.NewChildContext(opts) - return childCtx - } - - bootstrapStartTime, bootstrapEndTime := ctx.StartTime.Add(-interval), ctx.StartTime - transformerFn := func(bootstrapped, original ts.SeriesList) (ts.SeriesList, error) { - bootstrapList, err := combineBootstrapWithOriginal(ctx, - bootstrapStartTime, bootstrapEndTime, - bootstrapped, singlePathSpec(original)) - if err != nil { - return ts.NewSeriesList(), err - } - - results := make([]*ts.Series, 0, original.Len()) - - for i, bootstrap := range bootstrapList.Values { - series := original.Values[i] - windowPoints := int(interval / (time.Duration(series.MillisPerStep()) * time.Millisecond)) - if windowPoints <= 0 { - err := errors.NewInvalidParamsError(fmt.Errorf( - "non positive window points, windowSize=%s, stepSize=%d", - windowSize, series.MillisPerStep())) - return ts.NewSeriesList(), err - } - window := make([]float64, windowPoints) - util.Memset(window, math.NaN()) - numSteps := series.Len() - offset := bootstrap.Len() - numSteps - vals := ts.NewValues(ctx, series.MillisPerStep(), numSteps) - for i := 0; i < numSteps; i++ { - for j := i + offset - windowPoints; j < i+offset; j++ { - if j < 0 || j >= bootstrap.Len() { - continue - } - - idx := j - i - offset + windowPoints - if idx < 0 || idx > len(window)-1 { - continue - } - - window[idx] = bootstrap.ValueAt(j) - } - vals.SetValueAt(i, common.SafeSum(window)) - } - name := fmt.Sprintf("movingSum(%s,%q)", series.Name(), windowSize) - newSeries := ts.NewSeries(ctx, name, series.StartTime(), vals) - results = append(results, newSeries) - } - - original.Values = results - return original, nil - } - - return &binaryContextShifter{ - ContextShiftFunc: contextShiftingFn, - BinaryTransformer: transformerFn, - }, nil -} - - // legendValue takes one metric or a wildcard seriesList and a string in quotes. // Appends a value to the metric name in the legend. Currently one or several of: // "last", "avg", "total", "min", "max". @@ -1997,7 +1920,6 @@ func init() { MustRegisterFunction(mostDeviant) MustRegisterFunction(movingAverage) MustRegisterFunction(movingMedian) - MustRegisterFunction(movingSum) MustRegisterFunction(multiplySeries) MustRegisterFunction(nonNegativeDerivative).WithDefaultParams(map[uint8]interface{}{ 2: math.NaN(), // maxValue From 67b537877226f76d5e753c6991a4f6e8cc38d924 Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Thu, 3 Sep 2020 20:51:53 -0400 Subject: [PATCH 09/20] Apply suggestions from code review --- .../graphite/native/builtin_functions_test.go | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 9bd6bd6d23..29013c5c92 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -685,23 +685,6 @@ func TestMovingAverageError(t *testing.T) { testMovingFunctionError(t, "movingAverage(foo.bar.baz, 0)") } -func TestMovingSumSuccess(t *testing.T) { - values := []float64{12.0, 19.0, -10.0, math.NaN(), 10.0} - bootstrap := []float64{3.0, 4.0, 5.0} - expected := []float64{12.0, 21.0, 36.0, 21.0, 9.0} // (3+4+5), (4+5+12), (5+12+19), (12+19-10), (19-10+Nan) - - testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,\"30s\")", values, bootstrap, expected) - testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,3)", nil, nil, nil) - - bootstrapEntireSeries := []float64{3.0, 4.0, 5.0, 12.0, 19.0, -10.0, math.NaN(), 10.0} - testMovingAverage(t, "movingSum(foo.bar.baz, '30s')", "movingAverage(foo.bar.baz,\"30s\")", values, bootstrapEntireSeries, expected) -} - -func TestMovingSumError(t *testing.T) { - testMovingAverageError(t, "movingSum(foo.bar.baz, '-30s')") - testMovingAverageError(t, "movingSum(foo.bar.baz, 0)") -} - func TestIsNonNull(t *testing.T) { ctx := common.NewTestContext() defer ctx.Close() @@ -2564,7 +2547,7 @@ func TestMovingMedianInvalidLimits(t *testing.T) { func TestMovingMismatchedLimits(t *testing.T) { // NB: this tests the behavior when query limits do not snap exactly to data // points. When limits do not snap exactly, the first point should be omitted. - for _, fn := range []string{"movingAverage", "movingMedian", "movingSum"} { + for _, fn := range []string{"movingAverage", "movingMedian"} { for i := time.Duration(0); i < time.Minute; i += time.Second { testMovingAverageInvalidLimits(t, fn, i) } @@ -2978,7 +2961,6 @@ func TestFunctionsRegistered(t *testing.T) { "mostDeviant", "movingAverage", "movingMedian", - "movingSum", "multiplySeries", "nonNegativeDerivative", "nPercentile", From fabdacbe533500129f5e3c6667d4688599444da6 Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Thu, 3 Sep 2020 18:35:09 -0700 Subject: [PATCH 10/20] finished basic logic, just need to write tests --- .../graphite/native/builtin_functions.go | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index a8541e7c0f..ebd12bb4c3 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -924,6 +924,87 @@ func integral(ctx *common.Context, input singlePathSpec) (ts.SeriesList, error) return r, nil } + +/* + +def integralByInterval(requestContext, seriesList, intervalUnit): + """ + This will do the same as integral() funcion, except resetting the total to 0 + at the given time in the parameter "from" + Useful for finding totals per hour/day/week/.. + + Example: + + .. code-block:: none + + &target=integralByInterval(company.sales.perMinute, "1d")&from=midnight-10days + + This would start at zero on the left side of the graph, adding the sales each + minute, and show the evolution of sales per day during the last 10 days. + """ + intervalDuration = int(abs(deltaseconds(parseTimeOffset(intervalUnit)))) + startTime = int(timestamp(requestContext['startTime'])) + results = [] + for series in seriesList: + newValues = [] + currentTime = series.start # current time within series iteration + current = 0.0 # current accumulated value + for val in series: + # reset integral value if crossing an interval boundary + if (currentTime - startTime)//intervalDuration != (currentTime - startTime - series.step)//intervalDuration: + current = 0.0 + if val is None: + # keep previous value since val can be None when resetting current to 0.0 + newValues.append(current) + else: + current += val + newValues.append(current) + currentTime += series.step + series.tags['integralByInterval'] = intervalUnit + newName = "integralByInterval(%s,'%s')" % (series.name, intervalUnit) + newSeries = series.copy(name=newName, values=newValues) + results.append(newSeries) + return results + + +*/ +// integralByInterval will do the same as integral funcion, except it resets the total to 0 +// at the given time in the parameter “from”. Useful for finding totals per hour/day/week. +func integralByInterval(ctx *common.Context, input singlePathSpec, intervalString string) (ts.SeriesList, error) { + intervalUnit, err := common.ParseInterval(intervalString) + if err != nil { + return ts.NewSeriesList(), err + } + results := make([]*ts.Series, 0, len(input.Values)) + for _, series := range input.Values { + stepsPerInterval := intervalUnit.Milliseconds() / int64(series.MillisPerStep()) + var stepCounter int64 = 0 + + outvals := ts.NewValues(ctx, series.MillisPerStep(), series.Len()) + var currentSum float64 + for i := 0; i < series.Len(); i++ { + if stepCounter > stepsPerInterval { + // startNewInterval + stepCounter = 0 + currentSum = 0.0 + } + n := series.ValueAt(i) + if math.IsNaN(n) { + currentSum += n + outvals.SetValueAt(i, currentSum) + } + stepCounter += 1 + } + + newName := fmt.Sprintf("integralByInterval(%s, %s)", series.Name(), intervalString) + results = append(results, ts.NewSeries(ctx, newName, series.StartTime(), outvals)) + } + + r := ts.SeriesList(input) + r.Values = results + return r, nil +} + // This is the opposite of the integral function. This is useful for taking a // running total metric and calculating the delta between subsequent data // points. From 70fc626a48bd61d39cc156257e9c2b0028ff8c60 Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Fri, 4 Sep 2020 09:32:08 -0700 Subject: [PATCH 11/20] completed testing for integralByInteral --- .../graphite/native/builtin_functions.go | 47 +------------------ .../graphite/native/builtin_functions_test.go | 31 ++++++++++++ 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index b910b3850c..bcfc845d09 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -924,50 +924,6 @@ func integral(ctx *common.Context, input singlePathSpec) (ts.SeriesList, error) return r, nil } - -/* - -def integralByInterval(requestContext, seriesList, intervalUnit): - """ - This will do the same as integral() funcion, except resetting the total to 0 - at the given time in the parameter "from" - Useful for finding totals per hour/day/week/.. - - Example: - - .. code-block:: none - - &target=integralByInterval(company.sales.perMinute, "1d")&from=midnight-10days - - This would start at zero on the left side of the graph, adding the sales each - minute, and show the evolution of sales per day during the last 10 days. - """ - intervalDuration = int(abs(deltaseconds(parseTimeOffset(intervalUnit)))) - startTime = int(timestamp(requestContext['startTime'])) - results = [] - for series in seriesList: - newValues = [] - currentTime = series.start # current time within series iteration - current = 0.0 # current accumulated value - for val in series: - # reset integral value if crossing an interval boundary - if (currentTime - startTime)//intervalDuration != (currentTime - startTime - series.step)//intervalDuration: - current = 0.0 - if val is None: - # keep previous value since val can be None when resetting current to 0.0 - newValues.append(current) - else: - current += val - newValues.append(current) - currentTime += series.step - series.tags['integralByInterval'] = intervalUnit - newName = "integralByInterval(%s,'%s')" % (series.name, intervalUnit) - newSeries = series.copy(name=newName, values=newValues) - results.append(newSeries) - return results - - -*/ // integralByInterval will do the same as integral funcion, except it resets the total to 0 // at the given time in the parameter “from”. Useful for finding totals per hour/day/week. func integralByInterval(ctx *common.Context, input singlePathSpec, intervalString string) (ts.SeriesList, error) { @@ -989,7 +945,7 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin currentSum = 0.0 } n := series.ValueAt(i) - if math.IsNaN(n) { + if !math.IsNaN(n) { currentSum += n outvals.SetValueAt(i, currentSum) } @@ -1983,6 +1939,7 @@ func init() { MustRegisterFunction(holtWintersForecast) MustRegisterFunction(identity) MustRegisterFunction(integral) + MustRegisterFunction(integralByInterval) MustRegisterFunction(isNonNull) MustRegisterFunction(keepLastValue).WithDefaultParams(map[uint8]interface{}{ 2: -1, // limit diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 29013c5c92..8f27fdefd6 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -1699,6 +1699,36 @@ func TestIntegral(t *testing.T) { } } +func TestIntegralByInterval(t *testing.T) { + ctx := common.NewTestContext() + defer ctx.Close() + + invals := []float64{ + 0, 1, 2, 3, 4, 5, 6, math.NaN(), 8, math.NaN(), + } + + outvals := []float64{ + 0, 1, 3, 6, 4, 9, 15, math.NaN(), 8, math.NaN(), + } + + series := ts.NewSeries(ctx, "hello", time.Now(), + common.NewTestSeriesValues(ctx, 10000, invals)) + + r, err := integralByInterval(ctx, singlePathSpec{ + Values: []*ts.Series{series}, + }, "30s") + require.NoError(t, err) + + output := r.Values + require.Equal(t, 1, len(output)) + assert.Equal(t, "integralByInterval(hello, 30s)", output[0].Name()) + assert.Equal(t, series.StartTime(), output[0].StartTime()) + require.Equal(t, len(outvals), output[0].Len()) + for i, expected := range outvals { + xtest.Equalish(t, expected, output[0].ValueAt(i), "incorrect value at %d", i) + } +} + func TestDerivative(t *testing.T) { ctx := common.NewTestContext() defer ctx.Close() @@ -2944,6 +2974,7 @@ func TestFunctionsRegistered(t *testing.T) { "holtWintersForecast", "identity", "integral", + "integralByInterval", "isNonNull", "keepLastValue", "legendValue", From 0f425b9dcef92e1dc1ef794bc65000ff7b7a24af Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Fri, 11 Sep 2020 08:55:53 -0700 Subject: [PATCH 12/20] Update src/query/graphite/native/builtin_functions.go --- src/query/graphite/native/builtin_functions.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 1168bf6a5e..60fdd4f0e5 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1009,11 +1009,12 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin } results := make([]*ts.Series, 0, len(input.Values)) for _, series := range input.Values { - stepsPerInterval := intervalUnit.Milliseconds() / int64(series.MillisPerStep()) - var stepCounter int64 = 0 - - outvals := ts.NewValues(ctx, series.MillisPerStep(), series.Len()) - var currentSum float64 +var ( + stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) + vals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) + stepCounter int64 + currentSum float64 +) for i := 0; i < series.Len(); i++ { if stepCounter > stepsPerInterval { // startNewInterval From deb483e96e4c1e4bc3a2a9d4caefd7e9bf3f23a2 Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Fri, 11 Sep 2020 09:16:23 -0700 Subject: [PATCH 13/20] made variables more Go-like --- src/query/graphite/native/builtin_functions.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 60fdd4f0e5..c30d6681d2 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1008,13 +1008,15 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin return ts.NewSeriesList(), err } results := make([]*ts.Series, 0, len(input.Values)) + for _, series := range input.Values { -var ( - stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) - vals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) - stepCounter int64 - currentSum float64 -) + var ( + stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) + outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) + stepCounter int64 + currentSum float64 + ) + for i := 0; i < series.Len(); i++ { if stepCounter > stepsPerInterval { // startNewInterval @@ -1024,13 +1026,13 @@ var ( n := series.ValueAt(i) if !math.IsNaN(n) { currentSum += n - outvals.SetValueAt(i, currentSum) + outVals.SetValueAt(i, currentSum) } stepCounter += 1 } newName := fmt.Sprintf("integralByInterval(%s, %s)", series.Name(), intervalString) - results = append(results, ts.NewSeries(ctx, newName, series.StartTime(), outvals)) + results = append(results, ts.NewSeries(ctx, newName, series.StartTime(), outVals)) } r := ts.SeriesList(input) From a912b30d1514a3a83d78fd01a86e3ac7fd9f43cc Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Mon, 21 Sep 2020 08:48:17 -0700 Subject: [PATCH 14/20] Update src/query/graphite/native/builtin_functions.go --- src/query/graphite/native/builtin_functions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 9c95da170c..20da651397 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1099,7 +1099,7 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin var ( stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) - stepCounter int64 + stepCounter int64 = 0 currentSum float64 ) From 03ad7d55c336ffaa3c17a2807b14b4ba4a3bf7a8 Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Mon, 21 Sep 2020 08:49:11 -0700 Subject: [PATCH 15/20] Apply suggestions from code review --- src/query/graphite/native/builtin_functions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 20da651397..b466772961 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1100,7 +1100,7 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) stepCounter int64 = 0 - currentSum float64 + currentSum float64 = 0.0 ) for i := 0; i < series.Len(); i++ { From 970ed5c3ec513b83436fc7758f8af898db58d52b Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Mon, 21 Sep 2020 09:00:46 -0700 Subject: [PATCH 16/20] Ran go fmt --- .../graphite/native/builtin_functions.go | 23 +++++++-------- .../graphite/native/builtin_functions_test.go | 28 +++++++++---------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index b466772961..db61aa2079 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -271,7 +271,7 @@ func delay( func delayValuesHelper(ctx *common.Context, series *ts.Series, steps int) ts.Values { output := ts.NewValues(ctx, series.MillisPerStep(), series.Len()) for i := steps; i < series.Len(); i++ { - output.SetValueAt(i, series.ValueAt(i - steps)) + output.SetValueAt(i, series.ValueAt(i-steps)) } return output } @@ -281,7 +281,7 @@ func delayValuesHelper(ctx *common.Context, series *ts.Series, steps int) ts.Val // Useful for filtering out a part of a series of data from a wider range of data. func timeSlice(ctx *common.Context, inputPath singlePathSpec, start string, end string) (ts.SeriesList, error) { var ( - now = time.Now() + now = time.Now() tzOffsetForAbsoluteTime time.Duration ) startTime, err := graphite.ParseTime(start, now, tzOffsetForAbsoluteTime) @@ -633,8 +633,8 @@ func lowestCurrent(_ *common.Context, input singlePathSpec, n int) (ts.SeriesLis type windowSizeFunc func(stepSize int) int type windowSizeParsed struct { - deltaValue time.Duration - stringValue string + deltaValue time.Duration + stringValue string windowSizeFunc windowSizeFunc } @@ -841,7 +841,7 @@ func exponentialMovingAverage(ctx *common.Context, input singlePathSpec, windowS curr := bootstrap.ValueAt(i + offset) if !math.IsNaN(curr) { // formula: ema(current) = constant * (Current Value) + (1 - constant) * ema(previous) - ema = emaConstant * curr + (1 - emaConstant) * ema + ema = emaConstant*curr + (1-emaConstant)*ema vals.SetValueAt(i, ema) } else { vals.SetValueAt(i, math.NaN()) @@ -1097,10 +1097,10 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin for _, series := range input.Values { var ( - stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) - outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) - stepCounter int64 = 0 - currentSum float64 = 0.0 + stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) + outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) + stepCounter int64 = 0 + currentSum float64 = 0.0 ) for i := 0; i < series.Len(); i++ { @@ -1838,8 +1838,6 @@ func movingMinHelper(window []float64, vals ts.MutableValues, windowPoints int, } } - - func newMovingBinaryTransform( ctx *common.Context, input singlePathSpec, @@ -1870,7 +1868,7 @@ func newMovingBinaryTransform( bootstrapStartTime, bootstrapEndTime := ctx.StartTime.Add(-interval), ctx.StartTime return &binaryContextShifter{ - ContextShiftFunc: contextShiftingFn, + ContextShiftFunc: contextShiftingFn, BinaryTransformer: func(bootstrapped, original ts.SeriesList) (ts.SeriesList, error) { bootstrapList, err := combineBootstrapWithOriginal(ctx, bootstrapStartTime, bootstrapEndTime, @@ -1950,7 +1948,6 @@ func movingMin(ctx *common.Context, input singlePathSpec, windowSize genericInte return newMovingBinaryTransform(ctx, input, windowSize, "movingMin", movingMinHelper) } - // legendValue takes one metric or a wildcard seriesList and a string in quotes. // Appends a value to the metric name in the legend. Currently one or several of: // "last", "avg", "total", "min", "max". diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index eee7f776ef..9137cd6c1a 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -643,8 +643,8 @@ func testMovingFunction(t *testing.T, target, expectedName string, values, boots } var ( - testGeneralFunctionStart = time.Now().Add(time.Minute * -11).Truncate(time.Minute) - testGeneralFunctionEnd = time.Now().Add(time.Minute * -3).Truncate(time.Minute) + testGeneralFunctionStart = time.Now().Add(time.Minute * -11).Truncate(time.Minute) + testGeneralFunctionEnd = time.Now().Add(time.Minute * -3).Truncate(time.Minute) ) // testGeneralFunction is a copy of testMovingFunction but without any logic for bootstrapping values @@ -654,8 +654,8 @@ func testGeneralFunction(t *testing.T, target, expectedName string, values, outp engine := NewEngine( &common.MovingFunctionStorage{ - StepMillis: 60000, - Values: values, + StepMillis: 60000, + Values: values, }, ) phonyContext := common.NewContext(common.ContextOptions{ @@ -694,11 +694,11 @@ func TestMovingAverageSuccess(t *testing.T) { func TestExponentialMovingAverageSuccess(t *testing.T) { tests := []struct { - target string + target string expectedName string - bootstrap []float64 - inputs []float64 - expected []float64 + bootstrap []float64 + inputs []float64 + expected []float64 }{ { "exponentialMovingAverage(foo.bar.baz, 3)", @@ -3013,8 +3013,8 @@ func TestDelay(t *testing.T) { } var ( - testDelayStart = time.Now().Truncate(time.Minute) - testDelayEnd = testMovingFunctionEnd.Add(time.Minute) + testDelayStart = time.Now().Truncate(time.Minute) + testDelayEnd = testMovingFunctionEnd.Add(time.Minute) ) func testDelay(t *testing.T, target, expectedName string, values, output []float64) { @@ -3023,8 +3023,8 @@ func testDelay(t *testing.T, target, expectedName string, values, output []float engine := NewEngine( &common.MovingFunctionStorage{ - StepMillis: 10000, - Values: values, + StepMillis: 10000, + Values: values, }, ) phonyContext := common.NewContext(common.ContextOptions{ @@ -3050,8 +3050,8 @@ func testDelay(t *testing.T, target, expectedName string, values, output []float } func TestTimeSlice(t *testing.T) { - values := []float64{math.NaN(),1.0,2.0,3.0,math.NaN(),5.0,6.0,math.NaN(),7.0,8.0,9.0} - expected := []float64{math.NaN(),math.NaN(),math.NaN(),3.0,math.NaN(),5.0,6.0,math.NaN(),7.0,math.NaN(),math.NaN()} + values := []float64{math.NaN(), 1.0, 2.0, 3.0, math.NaN(), 5.0, 6.0, math.NaN(), 7.0, 8.0, 9.0} + expected := []float64{math.NaN(), math.NaN(), math.NaN(), 3.0, math.NaN(), 5.0, 6.0, math.NaN(), 7.0, math.NaN(), math.NaN()} testGeneralFunction(t, "timeSlice(foo.bar.baz, '-9min','-3min')", "timeSlice(foo.bar.baz, -9min, -3min)", values, expected) } From b0155f43ec553efe82fc75df9a128ff7af91b559 Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Mon, 21 Sep 2020 09:27:09 -0700 Subject: [PATCH 17/20] Added proper test case from graphite-web source code --- src/query/graphite/native/builtin_functions.go | 4 ++-- .../graphite/native/builtin_functions_test.go | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index db61aa2079..6f0cd2fc15 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1104,7 +1104,7 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin ) for i := 0; i < series.Len(); i++ { - if stepCounter > stepsPerInterval { + if stepCounter == stepsPerInterval { // startNewInterval stepCounter = 0 currentSum = 0.0 @@ -1112,8 +1112,8 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin n := series.ValueAt(i) if !math.IsNaN(n) { currentSum += n - outVals.SetValueAt(i, currentSum) } + outVals.SetValueAt(i, currentSum) stepCounter += 1 } diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 9137cd6c1a..fc3d343572 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -1823,29 +1823,33 @@ func TestIntegral(t *testing.T) { } } +/* + seriesList = self._gen_series_list_with_data(key='test',start=0,end=600,step=60,data=[None, 1, 2, 3, 4, 5, None, 6, 7, 8]) + expected = [TimeSeries("integralByInterval(test,'2min')", 0, 600, 60, [0, 1, 2, 5, 4, 9, 0, 6, 7, 15])] +*/ func TestIntegralByInterval(t *testing.T) { ctx := common.NewTestContext() defer ctx.Close() invals := []float64{ - 0, 1, 2, 3, 4, 5, 6, math.NaN(), 8, math.NaN(), + math.NaN(), 1, 2, 3, 4, 5, math.NaN(), 6, 7, 8, } outvals := []float64{ - 0, 1, 3, 6, 4, 9, 15, math.NaN(), 8, math.NaN(), + 0, 1, 2, 5, 4, 9, 0, 6, 7, 15, } series := ts.NewSeries(ctx, "hello", time.Now(), - common.NewTestSeriesValues(ctx, 10000, invals)) + common.NewTestSeriesValues(ctx, 60000, invals)) r, err := integralByInterval(ctx, singlePathSpec{ Values: []*ts.Series{series}, - }, "30s") + }, "2min") require.NoError(t, err) output := r.Values require.Equal(t, 1, len(output)) - assert.Equal(t, "integralByInterval(hello, 30s)", output[0].Name()) + assert.Equal(t, "integralByInterval(hello, 2min)", output[0].Name()) assert.Equal(t, series.StartTime(), output[0].StartTime()) require.Equal(t, len(outvals), output[0].Len()) for i, expected := range outvals { From 6f85d3c35bc7733c23b972e4a2789b835188d57e Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Mon, 21 Sep 2020 09:28:37 -0700 Subject: [PATCH 18/20] Apply suggestions from code review --- src/query/graphite/native/builtin_functions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 6f0cd2fc15..53e2b70433 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1099,7 +1099,7 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin var ( stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) - stepCounter int64 = 0 + stepCounter int64 currentSum float64 = 0.0 ) From 678690ad63c751af7acdb6e52a5de229944a000f Mon Sep 17 00:00:00 2001 From: teddywahle <69990143+teddywahle@users.noreply.github.com> Date: Mon, 21 Sep 2020 09:28:52 -0700 Subject: [PATCH 19/20] Apply suggestions from code review --- src/query/graphite/native/builtin_functions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 53e2b70433..c5cbfbbc61 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1100,7 +1100,7 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) stepCounter int64 - currentSum float64 = 0.0 + currentSum float64 ) for i := 0; i < series.Len(); i++ { From 6cabbd48da70adc7db8464c876458af266a090d3 Mon Sep 17 00:00:00 2001 From: Theodore Wahle Date: Mon, 21 Sep 2020 09:30:43 -0700 Subject: [PATCH 20/20] fixed formatting --- src/query/graphite/native/builtin_functions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index c5cbfbbc61..367c0f76ed 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1097,8 +1097,8 @@ func integralByInterval(ctx *common.Context, input singlePathSpec, intervalStrin for _, series := range input.Values { var ( - stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) - outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) + stepsPerInterval = intervalUnit.Milliseconds() / int64(series.MillisPerStep()) + outVals = ts.NewValues(ctx, series.MillisPerStep(), series.Len()) stepCounter int64 currentSum float64 )