From b781bf6bd1a3e7ee9d41632e7ecd143f423f1cee Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sat, 30 Jan 2021 01:13:26 -0500 Subject: [PATCH 01/11] [query] Fix Graphite asPercent function to handle nodes and multiple total divisor series --- .../graphite/native/builtin_functions.go | 249 ++++++++++++------ .../graphite/native/builtin_functions_test.go | 59 ++--- 2 files changed, 196 insertions(+), 112 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 61beb1ff90..7aa5cadc6c 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1013,111 +1013,196 @@ func asPercent(ctx *common.Context, input singlePathSpec, total genericInterface return ts.SeriesList(input), nil } - var toNormalize, normalized []*ts.Series - var tf totalFunc - var totalText string + if len(nodes) > 0 { + metaSeries := getMetaSeriesGrouping(input, nodes) + totalSeries := make(map[string]*ts.Series) + + switch totalArg := total.(type) { + case nil: + for k, series := range metaSeries { + if len(series) == 1 { + totalSeries[k] = series[0] + } else { + group, err := sumSeries(ctx, multiplePathSpecs(ts.NewSeriesListWithSeries(series...))) + if err != nil { + return ts.NewSeriesList(), err + } + totalSeries[k] = group.Values[0] + } + } + case ts.SeriesList, singlePathSpec: + var total ts.SeriesList + switch v := totalArg.(type) { + case ts.SeriesList: + total = v + case singlePathSpec: + total = ts.SeriesList(v) + } + totalGroups := getMetaSeriesGrouping(singlePathSpec(total), nodes) + for k, series := range totalGroups { + if len(series) == 1 { + totalSeries[k] = series[0] + } else { + group, err := sumSeries(ctx, multiplePathSpecs(ts.NewSeriesListWithSeries(series...))) + if err != nil { + return ts.NewSeriesList(), err + } + totalSeries[k] = group.Values[0] + } + } + default: + return ts.NewSeriesList(), errors.NewInvalidParamsError(fmt.Errorf("total must be nil or series list")) + } - switch totalArg := total.(type) { - case ts.SeriesList, singlePathSpec: - var total ts.SeriesList - switch v := totalArg.(type) { - case ts.SeriesList: - total = v - case singlePathSpec: - total = ts.SeriesList(v) + keys := make([]string, 0, len(metaSeries)+len(totalSeries)) + // Create meta series keys copy. + for k := range metaSeries { + keys = append(keys, k) } - if total.Len() == 0 { - // normalize input and sum up input as the total series - toNormalize = input.Values - tf = func(idx int, _ *ts.Series) float64 { return totalBySum(normalized, idx) } - } else { - if len(nodes) > 0 { - // group the series by specified nodes and then sum those groups - groupedTotal, err := groupByNodes(ctx, input, "sum", nodes...) + // Add any missing keys from totals. + for k := range totalSeries { + if _, ok := metaSeries[k]; ok { + continue + } + keys = append(keys, k) + } + + results := make([]*ts.Series, 0, len(metaSeries)) + for _, k := range keys { + seriesList, ok := metaSeries[k] + if !ok { + total := totalSeries[k] + newName := fmt.Sprintf("asPercent(MISSING,%s)", total.Name()) + nanValues := ts.NewConstantValues(ctx, math.NaN(), total.Len(), total.MillisPerStep()) + newSeries := ts.NewSeries(ctx, newName, total.StartTime(), nanValues) + results = append(results, newSeries) + continue + } + + for _, series := range seriesList { + total, ok := totalSeries[k] + if !ok { + newName := fmt.Sprintf("asPercent(%s,MISSING)", series.Name()) + nanValues := ts.NewConstantValues(ctx, math.NaN(), series.Len(), series.MillisPerStep()) + newSeries := ts.NewSeries(ctx, newName, series.StartTime(), nanValues) + results = append(results, newSeries) + continue + } + + normalized, start, _, millisPerStep, err := common.Normalize(ctx, + ts.NewSeriesListWithSeries(series, total)) if err != nil { return ts.NewSeriesList(), err } - toNormalize = append(input.Values, groupedTotal.Values[0]) - metaSeriesSumByKey := make(map[string]*ts.Series) - // map the aggregation key to the aggregated series - for _, series := range groupedTotal.Values { - metaSeriesSumByKey[series.Name()] = series + steps := normalized.Values[0].Len() + values := ts.NewValues(ctx, millisPerStep, steps) + for i := 0; i < steps; i++ { + v, t := normalized.Values[0].ValueAt(i), normalized.Values[1].ValueAt(i) + if !math.IsNaN(v) && !math.IsNaN(t) && t != 0 { + values.SetValueAt(i, (v/t)*100.0) + } } - tf = func(idx int, series *ts.Series) float64 { - // find which aggregation key this series falls under - // and return the sum for that aggregated group - key := getAggregationKey(series, nodes) - return metaSeriesSumByKey[key].ValueAt(idx) - } - totalText = groupedTotal.Values[0].Name() - } else { - toNormalize = append(input.Values, total.Values[0]) - tf = func(idx int, _ *ts.Series) float64 { return normalized[len(normalized)-1].ValueAt(idx) } - totalText = total.Values[0].Name() + newName := fmt.Sprintf("asPercent(%s,%s)", series.Name(), total.Name()) + divided := ts.NewSeries(ctx, newName, start, values) + results = append(results, divided) } } + + result := ts.NewSeriesList() + result.Values = results + return result, nil + } + + var totalSeriesList ts.SeriesList + switch totalArg := total.(type) { case float64: - toNormalize = input.Values - tf = func(idx int, _ *ts.Series) float64 { return totalArg } - totalText = fmt.Sprintf(common.FloatingPointFormat, totalArg) + // No normalization required, simply divide each by constant. + results := make([]*ts.Series, 0, len(input.Values)) + totalText := fmt.Sprintf(common.FloatingPointFormat, totalArg) + for _, series := range input.Values { + steps := series.Len() + values := ts.NewValues(ctx, series.MillisPerStep(), steps) + for i := 0; i < steps; i++ { + v, t := series.ValueAt(i), totalArg + if !math.IsNaN(v) && !math.IsNaN(t) && t != 0 { + values.SetValueAt(i, (v/t)*100.0) + } + } + newName := fmt.Sprintf("asPercent(%s,%s)", series.Name(), totalText) + divided := ts.NewSeries(ctx, newName, series.StartTime(), values) + results = append(results, divided) + } + result := ts.NewSeriesList() + result.Values = results + return result, nil case nil: - // if total is nil, the total is the sum of all the input series - toNormalize = input.Values - var err error - summedSeries, err := sumSeries(ctx, multiplePathSpecs(input)) + // Totals of the total sum. + sum, err := sumSeries(ctx, multiplePathSpecs(input)) if err != nil { return ts.NewSeriesList(), err } - tf = func(idx int, _ *ts.Series) float64 { return summedSeries.Values[0].ValueAt(idx) } - totalText = summedSeries.Values[0].Name() + totalSeriesList = sum + case ts.SeriesList, singlePathSpec: + // Total of a single series or same number of matching series. + var total ts.SeriesList + switch v := totalArg.(type) { + case ts.SeriesList: + total = v + case singlePathSpec: + total = ts.SeriesList(v) + } + if total.Len() != 0 && total.Len() != 1 && total.Len() != len(input.Values) { + return ts.NewSeriesList(), errors.NewInvalidParamsError(fmt.Errorf( + "require total to be nil, float, single series or same number of series: series=%d, total=%d", + len(input.Values), total.Len())) + } + if total.Len() == 0 { + // Same as nil take as sum of input. + sum, err := sumSeries(ctx, multiplePathSpecs(input)) + if err != nil { + return ts.NewSeriesList(), err + } + totalSeriesList = sum + } else { + totalSeriesList = total + } default: - err := errors.NewInvalidParamsError(errors.New("total must be either an int, a series, or nil")) + err := errors.NewInvalidParamsError(errors.New( + "total must be either an nil, float, a series or same number of series")) return ts.NewSeriesList(), err } - result, _, _, _, err := common.Normalize(ctx, ts.SeriesList{ - Values: toNormalize, - Metadata: input.Metadata, - }) - if err != nil { - return ts.NewSeriesList(), err - } + results := make([]*ts.Series, 0, len(input.Values)) + for idx, series := range input.Values { + totalSeries := totalSeriesList.Values[0] + if totalSeriesList.Len() != 1 { + // Divide each by their matching total if matching + // number of total, + totalSeries = totalSeriesList.Values[idx] + } + normalized, start, _, millisPerStep, err := common.Normalize(ctx, + ts.NewSeriesListWithSeries(series, totalSeries)) + if err != nil { + return ts.NewSeriesList(), nil + } - normalized = result.Values - numInputSeries := len(input.Values) - values := make([]ts.MutableValues, 0, numInputSeries) - for i := 0; i < numInputSeries; i++ { - percents := ts.NewValues(ctx, normalized[i].MillisPerStep(), normalized[i].Len()) - values = append(values, percents) - } - for i := 0; i < normalized[0].Len(); i++ { - for j := 0; j < numInputSeries; j++ { - t := tf(i, normalized[j]) - v := normalized[j].ValueAt(i) + steps := normalized.Values[0].Len() + values := ts.NewValues(ctx, millisPerStep, steps) + for i := 0; i < steps; i++ { + v, t := normalized.Values[0].ValueAt(i), normalized.Values[1].ValueAt(i) if !math.IsNaN(v) && !math.IsNaN(t) && t != 0 { - values[j].SetValueAt(i, 100.0*v/t) + values.SetValueAt(i, (v/t)*100.0) } } + newName := fmt.Sprintf("asPercent(%s,%s)", series.Name(), totalSeries.Name()) + divided := ts.NewSeries(ctx, newName, start, values) + results = append(results, divided) } - - results := make([]*ts.Series, 0, numInputSeries) - for i := 0; i < numInputSeries; i++ { - var totalName string - if len(totalText) == 0 { - totalName = normalized[i].Specification - } else { - totalName = totalText - } - newName := fmt.Sprintf("asPercent(%s, %s)", normalized[i].Name(), totalName) - newSeries := ts.NewSeries(ctx, newName, normalized[i].StartTime(), values[i]) - results = append(results, newSeries) - } - - r := ts.SeriesList(input) - r.Values = results - return r, nil + result := ts.NewSeriesList() + result.Values = results + return result, nil } // exclude takes a metric or a wildcard seriesList, followed by a regular @@ -2116,7 +2201,7 @@ func newMovingBinaryTransform( results := make([]*ts.Series, 0, original.Len()) maxWindowPoints := 0 - for i, _ := range bootstrapList.Values { + for i := range bootstrapList.Values { series := original.Values[i] windowPoints := windowPointsLength(series, interval) if windowPoints <= 0 { diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 5521e93645..142354d196 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -691,11 +691,11 @@ func TestTransformNull(t *testing.T) { }, 42.5, []common.TestSeries{ - common.TestSeries{ + { Name: "transformNull(foo1,42.500)", Data: []float64{0, 42.5, 2.0, 42.5, 3.0}, }, - common.TestSeries{ + { Name: "transformNull(foo2,42.500)", Data: []float64{42.5, 7, 2.0, 6.5, 42.5}, }, @@ -710,11 +710,11 @@ func TestTransformNull(t *testing.T) { }, -0.5, []common.TestSeries{ - common.TestSeries{ + { Name: "transformNull(foo1,-0.500)", Data: []float64{0, 1.0, 2.0, -0.5, 3.0}, }, - common.TestSeries{ + { Name: "transformNull(foo2,-0.500)", Data: []float64{-0.5, 7, -0.5, 6.5, -0.5}, }, @@ -1470,18 +1470,18 @@ func TestFallbackSeries(t *testing.T) { }{ { nil, - []common.TestSeries{common.TestSeries{"output", []float64{0, 1.0}}}, - []common.TestSeries{common.TestSeries{"output", []float64{0, 1.0}}}, + []common.TestSeries{{"output", []float64{0, 1.0}}}, + []common.TestSeries{{"output", []float64{0, 1.0}}}, }, { []common.TestSeries{}, - []common.TestSeries{common.TestSeries{"output", []float64{0, 1.0}}}, - []common.TestSeries{common.TestSeries{"output", []float64{0, 1.0}}}, + []common.TestSeries{{"output", []float64{0, 1.0}}}, + []common.TestSeries{{"output", []float64{0, 1.0}}}, }, { - []common.TestSeries{common.TestSeries{"output", []float64{0, 2.0}}}, - []common.TestSeries{common.TestSeries{"fallback", []float64{0, 1.0}}}, - []common.TestSeries{common.TestSeries{"output", []float64{0, 2.0}}}, + []common.TestSeries{{"output", []float64{0, 2.0}}}, + []common.TestSeries{{"fallback", []float64{0, 1.0}}}, + []common.TestSeries{{"output", []float64{0, 2.0}}}, }, } @@ -1905,7 +1905,7 @@ func TestAsPercentWithSeriesTotal(t *testing.T) { output := r.Values require.Equal(t, 1, len(output)) require.Equal(t, output[0].MillisPerStep(), test.outputStep) - assert.Equal(t, "asPercent(, )", output[0].Name()) + assert.Equal(t, "asPercent(,)", output[0].Name()) for step := 0; step < output[0].Len(); step++ { v := output[0].ValueAt(step) @@ -1949,7 +1949,7 @@ func TestAsPercentWithFloatTotal(t *testing.T) { output := r.Values require.Equal(t, 1, len(output)) require.Equal(t, output[0].MillisPerStep(), test.outputStep) - expectedName := fmt.Sprintf("asPercent(, "+common.FloatingPointFormat+")", + expectedName := fmt.Sprintf("asPercent(,"+common.FloatingPointFormat+")", test.total) assert.Equal(t, expectedName, output[0].Name()) @@ -1990,7 +1990,7 @@ func TestAsPercentWithNilTotal(t *testing.T) { output := r.Values require.Equal(t, 1, len(output)) require.Equal(t, output[0].MillisPerStep(), test.outputStep) - expectedName := fmt.Sprintf("asPercent(, sumSeries())") + expectedName := fmt.Sprintf("asPercent(,sumSeries())") assert.Equal(t, expectedName, output[0].Name()) for step := 0; step < output[0].Len(); step++ { @@ -2027,12 +2027,12 @@ func TestAsPercentWithSeriesList(t *testing.T) { values []float64 }{ { - "asPercent(foo, foo)", + "asPercent(foo,sumSeries(foo,bar))", 200, []float64{65.0, 100.0, 50.0}, }, { - "asPercent(bar, bar)", + "asPercent(bar,sumSeries(foo,bar))", 200, []float64{35.0, nan, 50.0}, }, @@ -2061,7 +2061,7 @@ func TestAsPercentWithSeriesList(t *testing.T) { } for _, totalArg := range []interface{}{ - ts.SeriesList{Values: []*ts.Series(nil)}, + nil, singlePathSpec{}, } { r, err := asPercent(ctx, singlePathSpec{ @@ -2080,7 +2080,6 @@ func TestAsPercentWithSeriesList(t *testing.T) { } } } - } func testLogarithm(t *testing.T, base int, indices []int) { @@ -2701,8 +2700,8 @@ func TestSquareRoot(t *testing.T) { inputSeries = append(inputSeries, series) } expected := []common.TestSeries{ - common.TestSeries{Name: "squareRoot(foo)", Data: []float64{1.0, nan, 1.73205, nan}}, - common.TestSeries{Name: "squareRoot(bar)", Data: []float64{2.0}}, + {Name: "squareRoot(foo)", Data: []float64{1.0, nan, 1.73205, nan}}, + {Name: "squareRoot(bar)", Data: []float64{2.0}}, } results, err := squareRoot(ctx, singlePathSpec{ Values: inputSeries, @@ -2744,7 +2743,7 @@ func TestStdev(t *testing.T) { inputSeries = append(inputSeries, series) } expected := []common.TestSeries{ - common.TestSeries{Name: "stddev(foo,3)", Data: []float64{0.0, 0.5, 0.8165, 0.8165, 0.5, 0.0, nan, 0.0, 0.5, 0.5, 0.0}}, + {Name: "stddev(foo,3)", Data: []float64{0.0, 0.5, 0.8165, 0.8165, 0.5, 0.0, nan, 0.0, 0.5, 0.5, 0.0}}, } results, err := stdev(ctx, singlePathSpec{ Values: inputSeries, @@ -2828,11 +2827,11 @@ func testPercentileFunction(t *testing.T, f percentileFunction, expected []commo func TestNPercentile(t *testing.T) { expected := []common.TestSeries{ - common.TestSeries{ + { Name: "nPercentile(bar, 40.123)", Data: []float64{3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0}, }, - common.TestSeries{ + { Name: "nPercentile(baz, 40.123)", Data: []float64{1.0}, }, @@ -2843,15 +2842,15 @@ func TestNPercentile(t *testing.T) { func TestRemoveAbovePercentile(t *testing.T) { nan := math.NaN() expected := []common.TestSeries{ - common.TestSeries{ + { Name: "removeAbovePercentile(foo, 40.123)", Data: []float64{nan, nan, nan, nan, nan}, }, - common.TestSeries{ + { Name: "removeAbovePercentile(bar, 40.123)", Data: []float64{3.0, 2.0, nan, nan, 1.0, nan, nan, nan}, }, - common.TestSeries{ + { Name: "removeAbovePercentile(baz, 40.123)", Data: []float64{1.0}, }, @@ -2864,15 +2863,15 @@ func TestRemoveBelowPercentile(t *testing.T) { nan := math.NaN() expected := []common.TestSeries{ - common.TestSeries{ + { Name: "removeBelowPercentile(foo, 40.123)", Data: []float64{nan, nan, nan, nan, nan}, }, - common.TestSeries{ + { Name: "removeBelowPercentile(bar, 40.123)", Data: []float64{3.0, nan, 4.0, nan, nan, 6.0, nan, 5.0}, }, - common.TestSeries{ + { Name: "removeBelowPercentile(baz, 40.123)", Data: []float64{1.0}, }, @@ -2975,7 +2974,7 @@ func TestChanged(t *testing.T) { ) expected := []common.TestSeries{ - common.TestSeries{ + { Name: "changed(foo)", Data: []float64{0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0}, }, From e8770882eeabc6e9fad367ed66810f9e08fc5020 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sat, 30 Jan 2021 01:17:45 -0500 Subject: [PATCH 02/11] Match series by name order when total matches input length --- src/query/graphite/native/builtin_functions.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 7aa5cadc6c..39482c4417 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1166,6 +1166,14 @@ func asPercent(ctx *common.Context, input singlePathSpec, total genericInterface } totalSeriesList = sum } else { + // Sort both by name so they get divided by same name if same length + // or closest match. + sort.Slice(input.Values, func(i, j int) bool { + return strings.Compare(input.Values[i].Name(), input.Values[j].Name()) < 0 + }) + sort.Slice(total.Values, func(i, j int) bool { + return strings.Compare(total.Values[i].Name(), total.Values[j].Name()) < 0 + }) totalSeriesList = total } default: From 7c79a3b9e9c3d57b4e55c3128a0eba7a85c8df35 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sat, 30 Jan 2021 01:18:20 -0500 Subject: [PATCH 03/11] Fix comment typo --- 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 39482c4417..944ec6e22e 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1187,7 +1187,7 @@ func asPercent(ctx *common.Context, input singlePathSpec, total genericInterface totalSeries := totalSeriesList.Values[0] if totalSeriesList.Len() != 1 { // Divide each by their matching total if matching - // number of total, + // number of total. totalSeries = totalSeriesList.Values[idx] } normalized, start, _, millisPerStep, err := common.Normalize(ctx, From 99b564cacea3abc62750b08fe0e4a694b58a8929 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sun, 31 Jan 2021 00:42:27 -0500 Subject: [PATCH 04/11] Match length of total to input --- 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 944ec6e22e..2ee702ae8f 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1185,7 +1185,7 @@ func asPercent(ctx *common.Context, input singlePathSpec, total genericInterface results := make([]*ts.Series, 0, len(input.Values)) for idx, series := range input.Values { totalSeries := totalSeriesList.Values[0] - if totalSeriesList.Len() != 1 { + if totalSeriesList.Len() == len(input.Values) { // Divide each by their matching total if matching // number of total. totalSeries = totalSeriesList.Values[idx] From 1d4acf5a3b2bee35d2a0bff5d52c1aaa8e39b025 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sun, 31 Jan 2021 02:08:40 -0500 Subject: [PATCH 05/11] Add tests for nodes and multiple total series case --- .../graphite/native/builtin_functions.go | 2 + .../graphite/native/builtin_functions_test.go | 333 ++++++++++++++++++ 2 files changed, 335 insertions(+) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 2ee702ae8f..cc597206e1 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -1066,6 +1066,8 @@ func asPercent(ctx *common.Context, input singlePathSpec, total genericInterface } keys = append(keys, k) } + // Sort keys for determinism and test result. + sort.Strings(keys) results := make([]*ts.Series, 0, len(metaSeries)) for _, k := range keys { diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 142354d196..c5c903bd58 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -2082,6 +2082,339 @@ func TestAsPercentWithSeriesList(t *testing.T) { } } +func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { + ctx := common.NewTestContext() + defer ctx.Close() + + nan := math.NaN() + inputs := []struct { + name string + step int + values []float64 + }{ + { + "foo.value", + 100, + []float64{12.0, 14.0, 16.0, nan, 20.0, 30.0}, + }, + { + "bar.value", + 200, + []float64{7.0, nan, 25.0}, + }, + } + totals := []struct { + name string + step int + values []float64 + }{ + { + "foo.total", + 100, + []float64{24.0, 28.0, 48.0, nan, 40.0, 60.0}, + }, + { + "bar.total", + 200, + []float64{14.0, nan, 75.0}, + }, + } + outputs := []struct { + name string + step int + values []float64 + }{ + { + "asPercent(bar.value,bar.total)", + 200, + []float64{50.0, nan, 33.33333333333333}, + }, + { + "asPercent(foo.value,foo.total)", + 100, + []float64{50.0, 50.0, 33.33333333333333, nan, 50.0, 50.0}, + }, + } + + var inputSeries []*ts.Series + for _, input := range inputs { + timeSeries := ts.NewSeries( + ctx, + input.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, input.step, input.values), + ) + inputSeries = append(inputSeries, timeSeries) + } + + var totalSeries []*ts.Series + for _, input := range totals { + timeSeries := ts.NewSeries( + ctx, + input.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, input.step, input.values), + ) + totalSeries = append(totalSeries, timeSeries) + } + + var expected []*ts.Series + for _, output := range outputs { + timeSeries := ts.NewSeries( + ctx, + output.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, output.step, output.values), + ) + expected = append(expected, timeSeries) + } + + r, err := asPercent(ctx, singlePathSpec{ + Values: inputSeries, + }, singlePathSpec{ + Values: totalSeries, + }) + require.NoError(t, err) + + results := r.Values + require.Equal(t, len(expected), len(results)) + for i := 0; i < len(results); i++ { + require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) + require.Equal(t, expected[i].Len(), results[i].Len()) + require.Equal(t, expected[i].Name(), results[i].Name()) + for step := 0; step < results[i].Len(); step++ { + xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) + } + } +} + +func TestAsPercentWithNodesAndTotalNil(t *testing.T) { + ctx := common.NewTestContext() + defer ctx.Close() + + inputs := []struct { + name string + step int + values []float64 + }{ + { + "cpu.foo.core1", + 200, + []float64{12.0, 5.0, 48.0}, + }, + { + "cpu.foo.core2", + 200, + []float64{12.0, 15.0, 16.0}, + }, + { + "cpu.bar.core1", + 200, + []float64{12.0, 14.0, 16.0}, + }, + } + outputs := []struct { + name string + step int + values []float64 + }{ + { + "asPercent(cpu.bar.core1,cpu.bar.core1)", + 200, + []float64{100.0, 100.0, 100.0}, + }, + { + "asPercent(cpu.foo.core1,sumSeries(cpu.foo.core1,cpu.foo.core2))", + 200, + []float64{50.0, 25.0, 75.0}, + }, + { + "asPercent(cpu.foo.core2,sumSeries(cpu.foo.core1,cpu.foo.core2))", + 200, + []float64{50.0, 75.0, 25.0}, + }, + } + + var inputSeries []*ts.Series + for _, input := range inputs { + timeSeries := ts.NewSeries( + ctx, + input.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, input.step, input.values), + ) + inputSeries = append(inputSeries, timeSeries) + } + + var expected []*ts.Series + for _, output := range outputs { + timeSeries := ts.NewSeries( + ctx, + output.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, output.step, output.values), + ) + expected = append(expected, timeSeries) + } + + r, err := asPercent(ctx, singlePathSpec{ + Values: inputSeries, + }, nil, 1) + require.NoError(t, err) + + results := r.Values + require.Equal(t, len(expected), len(results)) + for i := 0; i < len(results); i++ { + require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) + require.Equal(t, expected[i].Len(), results[i].Len()) + require.Equal(t, expected[i].Name(), results[i].Name()) + for step := 0; step < results[i].Len(); step++ { + xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) + } + } +} + +func TestAsPercentWithNodesAndTotalSeriesList(t *testing.T) { + ctx := common.NewTestContext() + defer ctx.Close() + + nan := math.NaN() + inputs := []struct { + name string + step int + values []float64 + }{ + { + "cpu.foo.core1", + 200, + []float64{12.0, 5.0, 48.0}, + }, + { + "cpu.foo.core2", + 200, + []float64{12.0, 15.0, 16.0}, + }, + { + "cpu.bar.core1", + 200, + []float64{12.0, 14.0, 16.0}, + }, + { + "cpu.qux.core1", + 200, + []float64{12.0, 14.0, 16.0}, + }, + } + totals := []struct { + name string + step int + values []float64 + }{ + { + "cpu_cluster.foo.zone-a", + 200, + []float64{24.0, 40.0, 256.0}, + }, + { + "cpu_cluster.foo.zone-b", + 200, + []float64{24.0, 40.0, 256.0}, + }, + { + "cpu_cluster.bar", + 200, + []float64{48.0, 14.0, 16.0}, + }, + { + "cpu_cluster.baz", + 200, + []float64{12.0, 14.0, 16.0}, + }, + } + outputs := []struct { + name string + step int + values []float64 + }{ + { + "asPercent(cpu.bar.core1,cpu_cluster.bar)", + 200, + []float64{25.0, 100.0, 100.0}, + }, + { + "asPercent(MISSING,cpu_cluster.baz)", + 200, + []float64{nan, nan, nan}, + }, + { + "asPercent(cpu.foo.core1,sumSeries(cpu_cluster.foo.zone-a,cpu_cluster.foo.zone-b))", + 200, + []float64{25.0, 6.25, 9.375}, + }, + { + "asPercent(cpu.foo.core2,sumSeries(cpu_cluster.foo.zone-a,cpu_cluster.foo.zone-b))", + 200, + []float64{25.0, 18.75, 3.125}, + }, + { + "asPercent(cpu.qux.core1,MISSING)", + 200, + []float64{nan, nan, nan}, + }, + } + + var inputSeries []*ts.Series + for _, input := range inputs { + timeSeries := ts.NewSeries( + ctx, + input.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, input.step, input.values), + ) + inputSeries = append(inputSeries, timeSeries) + } + + var totalSeries []*ts.Series + for _, input := range totals { + timeSeries := ts.NewSeries( + ctx, + input.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, input.step, input.values), + ) + totalSeries = append(totalSeries, timeSeries) + } + + var expected []*ts.Series + for _, output := range outputs { + timeSeries := ts.NewSeries( + ctx, + output.name, + ctx.StartTime, + common.NewTestSeriesValues(ctx, output.step, output.values), + ) + expected = append(expected, timeSeries) + } + + r, err := asPercent(ctx, singlePathSpec{ + Values: inputSeries, + }, singlePathSpec{ + Values: totalSeries, + }, 1) + require.NoError(t, err) + + results := r.Values + require.Equal(t, len(expected), len(results)) + for i := 0; i < len(results); i++ { + require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) + require.Equal(t, expected[i].Len(), results[i].Len()) + require.Equal(t, expected[i].Name(), results[i].Name()) + for step := 0; step < results[i].Len(); step++ { + xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) + } + } +} + func testLogarithm(t *testing.T, base int, indices []int) { ctx := common.NewTestContext() defer ctx.Close() From d41fdd9f3efb4b07b337a001b649eb30a9dfa618 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sun, 31 Jan 2021 02:11:41 -0500 Subject: [PATCH 06/11] Fix lint --- .../graphite/native/builtin_functions_test.go | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index c5c903bd58..d141d0ce7e 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -1470,18 +1470,18 @@ func TestFallbackSeries(t *testing.T) { }{ { nil, - []common.TestSeries{{"output", []float64{0, 1.0}}}, - []common.TestSeries{{"output", []float64{0, 1.0}}}, + []common.TestSeries{{Name: "output", Data: []float64{0, 1.0}}}, + []common.TestSeries{{Name: "output", Data: []float64{0, 1.0}}}, }, { []common.TestSeries{}, - []common.TestSeries{{"output", []float64{0, 1.0}}}, - []common.TestSeries{{"output", []float64{0, 1.0}}}, + []common.TestSeries{{Name: "output", Data: []float64{0, 1.0}}}, + []common.TestSeries{{Name: "output", Data: []float64{0, 1.0}}}, }, { - []common.TestSeries{{"output", []float64{0, 2.0}}}, - []common.TestSeries{{"fallback", []float64{0, 1.0}}}, - []common.TestSeries{{"output", []float64{0, 2.0}}}, + []common.TestSeries{{Name: "output", Data: []float64{0, 2.0}}}, + []common.TestSeries{{Name: "fallback", Data: []float64{0, 1.0}}}, + []common.TestSeries{{Name: "output", Data: []float64{0, 2.0}}}, }, } @@ -1990,7 +1990,7 @@ func TestAsPercentWithNilTotal(t *testing.T) { output := r.Values require.Equal(t, 1, len(output)) require.Equal(t, output[0].MillisPerStep(), test.outputStep) - expectedName := fmt.Sprintf("asPercent(,sumSeries())") + expectedName := "asPercent(,sumSeries())" assert.Equal(t, expectedName, output[0].Name()) for step := 0; step < output[0].Len(); step++ { @@ -2530,8 +2530,8 @@ func TestInterpolate(t *testing.T) { start := time.Now() step := 100 for _, test := range tests { - input := []common.TestSeries{{"foo", test.values}} - expected := []common.TestSeries{{"interpolate(foo)", test.output}} + input := []common.TestSeries{{Name: "foo", Data: test.values}} + expected := []common.TestSeries{{Name: "interpolate(foo)", Data: test.output}} timeSeries := generateSeriesList(ctx, start, input, step) output, err := interpolate(ctx, singlePathSpec{ Values: timeSeries, @@ -2593,8 +2593,8 @@ func TestDerivative(t *testing.T) { start := time.Now() step := 100 for _, test := range tests { - input := []common.TestSeries{{"foo", test.values}} - expected := []common.TestSeries{{"derivative(foo)", test.output}} + input := []common.TestSeries{{Name: "foo", Data: test.values}} + expected := []common.TestSeries{{Name: "derivative(foo)", Data: test.output}} timeSeries := generateSeriesList(ctx, start, input, step) output, err := derivative(ctx, singlePathSpec{ Values: timeSeries, @@ -2629,8 +2629,8 @@ func TestNonNegativeDerivative(t *testing.T) { start := time.Now() step := 100 for _, test := range tests { - input := []common.TestSeries{{"foo", test.values}} - expected := []common.TestSeries{{"nonNegativeDerivative(foo)", test.output}} + input := []common.TestSeries{{Name: "foo", Data: test.values}} + expected := []common.TestSeries{{Name: "nonNegativeDerivative(foo)", Data: test.output}} timeSeries := generateSeriesList(ctx, start, input, step) output, err := nonNegativeDerivative(ctx, singlePathSpec{ Values: timeSeries, From 1960d909862d6f65155a9628ecfc055b309ee96c Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sun, 31 Jan 2021 02:18:22 -0500 Subject: [PATCH 07/11] Fix lint more --- .../graphite/native/builtin_functions_test.go | 50 ++++++------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index d141d0ce7e..7dba12710e 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -2084,7 +2084,7 @@ func TestAsPercentWithSeriesList(t *testing.T) { func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() inputs := []struct { @@ -2136,7 +2136,7 @@ func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { }, } - var inputSeries []*ts.Series + var inputSeries []*ts.Series // nolint: prealloc for _, input := range inputs { timeSeries := ts.NewSeries( ctx, @@ -2147,7 +2147,7 @@ func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { inputSeries = append(inputSeries, timeSeries) } - var totalSeries []*ts.Series + var totalSeries []*ts.Series // nolint: prealloc for _, input := range totals { timeSeries := ts.NewSeries( ctx, @@ -2158,7 +2158,7 @@ func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { totalSeries = append(totalSeries, timeSeries) } - var expected []*ts.Series + var expected []*ts.Series // nolint: prealloc for _, output := range outputs { timeSeries := ts.NewSeries( ctx, @@ -2175,8 +2175,10 @@ func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { Values: totalSeries, }) require.NoError(t, err) + requireEqual(t, expected, r.Values) +} - results := r.Values +func requireEqual(t *testing.T, expected, results []*ts.Series) { require.Equal(t, len(expected), len(results)) for i := 0; i < len(results); i++ { require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) @@ -2190,7 +2192,7 @@ func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { func TestAsPercentWithNodesAndTotalNil(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() inputs := []struct { name string @@ -2235,7 +2237,7 @@ func TestAsPercentWithNodesAndTotalNil(t *testing.T) { }, } - var inputSeries []*ts.Series + var inputSeries []*ts.Series // nolint: prealloc for _, input := range inputs { timeSeries := ts.NewSeries( ctx, @@ -2246,7 +2248,7 @@ func TestAsPercentWithNodesAndTotalNil(t *testing.T) { inputSeries = append(inputSeries, timeSeries) } - var expected []*ts.Series + var expected []*ts.Series // nolint: prealloc for _, output := range outputs { timeSeries := ts.NewSeries( ctx, @@ -2261,22 +2263,12 @@ func TestAsPercentWithNodesAndTotalNil(t *testing.T) { Values: inputSeries, }, nil, 1) require.NoError(t, err) - - results := r.Values - require.Equal(t, len(expected), len(results)) - for i := 0; i < len(results); i++ { - require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) - require.Equal(t, expected[i].Len(), results[i].Len()) - require.Equal(t, expected[i].Name(), results[i].Name()) - for step := 0; step < results[i].Len(); step++ { - xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) - } - } + requireEqual(t, expected, r.Values) } func TestAsPercentWithNodesAndTotalSeriesList(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() inputs := []struct { @@ -2363,7 +2355,7 @@ func TestAsPercentWithNodesAndTotalSeriesList(t *testing.T) { }, } - var inputSeries []*ts.Series + var inputSeries []*ts.Series // nolint: prealloc for _, input := range inputs { timeSeries := ts.NewSeries( ctx, @@ -2374,7 +2366,7 @@ func TestAsPercentWithNodesAndTotalSeriesList(t *testing.T) { inputSeries = append(inputSeries, timeSeries) } - var totalSeries []*ts.Series + var totalSeries []*ts.Series // nolint: prealloc for _, input := range totals { timeSeries := ts.NewSeries( ctx, @@ -2385,7 +2377,7 @@ func TestAsPercentWithNodesAndTotalSeriesList(t *testing.T) { totalSeries = append(totalSeries, timeSeries) } - var expected []*ts.Series + var expected []*ts.Series // nolint: prealloc for _, output := range outputs { timeSeries := ts.NewSeries( ctx, @@ -2402,17 +2394,7 @@ func TestAsPercentWithNodesAndTotalSeriesList(t *testing.T) { Values: totalSeries, }, 1) require.NoError(t, err) - - results := r.Values - require.Equal(t, len(expected), len(results)) - for i := 0; i < len(results); i++ { - require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) - require.Equal(t, expected[i].Len(), results[i].Len()) - require.Equal(t, expected[i].Name(), results[i].Name()) - for step := 0; step < results[i].Len(); step++ { - xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) - } - } + requireEqual(t, expected, r.Values) } func testLogarithm(t *testing.T, base int, indices []int) { From b7b431b262c4b83c4d3f0d83b1925348ba96dc2d Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Sun, 31 Jan 2021 02:19:38 -0500 Subject: [PATCH 08/11] Fix final duplication --- .../graphite/native/builtin_functions_test.go | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 7dba12710e..d64b82de52 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -2068,16 +2068,18 @@ func TestAsPercentWithSeriesList(t *testing.T) { Values: inputSeries, }, totalArg) require.NoError(t, err) + requireEqual(t, expected, r.Values) + } +} - results := r.Values - require.Equal(t, len(expected), len(results)) - for i := 0; i < len(results); i++ { - require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) - require.Equal(t, expected[i].Len(), results[i].Len()) - require.Equal(t, expected[i].Name(), results[i].Name()) - for step := 0; step < results[i].Len(); step++ { - xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) - } +func requireEqual(t *testing.T, expected, results []*ts.Series) { + require.Equal(t, len(expected), len(results)) + for i := 0; i < len(results); i++ { + require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) + require.Equal(t, expected[i].Len(), results[i].Len()) + require.Equal(t, expected[i].Name(), results[i].Name()) + for step := 0; step < results[i].Len(); step++ { + xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) } } } @@ -2178,18 +2180,6 @@ func TestAsPercentWithSeriesListAndTotalSeriesList(t *testing.T) { requireEqual(t, expected, r.Values) } -func requireEqual(t *testing.T, expected, results []*ts.Series) { - require.Equal(t, len(expected), len(results)) - for i := 0; i < len(results); i++ { - require.Equal(t, expected[i].MillisPerStep(), results[i].MillisPerStep()) - require.Equal(t, expected[i].Len(), results[i].Len()) - require.Equal(t, expected[i].Name(), results[i].Name()) - for step := 0; step < results[i].Len(); step++ { - xtest.Equalish(t, expected[i].ValueAt(step), results[i].ValueAt(step)) - } - } -} - func TestAsPercentWithNodesAndTotalNil(t *testing.T) { ctx := common.NewTestContext() defer func() { _ = ctx.Close() }() From 9558e911ed154cc4210a7b2219a276c8d96c13f4 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Wed, 17 Mar 2021 18:18:22 -0400 Subject: [PATCH 09/11] Fix lint --- src/query/graphite/common/basic_functions.go | 3 ++- .../graphite/native/aggregation_functions.go | 17 ++++++++--------- src/query/graphite/native/builtin_functions.go | 12 ++++++++---- .../graphite/native/builtin_functions_test.go | 1 + src/query/graphite/native/expression.go | 3 ++- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/query/graphite/common/basic_functions.go b/src/query/graphite/common/basic_functions.go index 6682945750..6ef9930657 100644 --- a/src/query/graphite/common/basic_functions.go +++ b/src/query/graphite/common/basic_functions.go @@ -187,7 +187,8 @@ func ParseInterval(fullInterval string) (time.Duration, error) { allIntervals := reInterval.FindAllString(fullInterval, -1) output := time.Duration(0) if allIntervals == nil { - return 0, xerrors.NewInvalidParamsError(fmt.Errorf("Unrecognized interval string: %s", fullInterval)) + return 0, xerrors.NewInvalidParamsError( + fmt.Errorf("unrecognized interval string: %s", fullInterval)) } for _, interval := range allIntervals { diff --git a/src/query/graphite/native/aggregation_functions.go b/src/query/graphite/native/aggregation_functions.go index ca557f7645..6d0846182b 100644 --- a/src/query/graphite/native/aggregation_functions.go +++ b/src/query/graphite/native/aggregation_functions.go @@ -31,7 +31,6 @@ import ( "github.com/m3db/m3/src/query/block" "github.com/m3db/m3/src/query/graphite/common" "github.com/m3db/m3/src/query/graphite/ts" - "github.com/m3db/m3/src/x/errors" xerrors "github.com/m3db/m3/src/x/errors" ) @@ -233,7 +232,7 @@ func divideSeries(ctx *common.Context, dividendSeriesList, divisorSeriesList sin return ts.NewSeriesList(), nil } if len(divisorSeriesList.Values) != 1 { - err := errors.NewInvalidParamsError(fmt.Errorf( + err := xerrors.NewInvalidParamsError(fmt.Errorf( "divideSeries second argument must reference exactly one series but instead has %d", len(divisorSeriesList.Values))) return ts.NewSeriesList(), err @@ -258,7 +257,7 @@ func divideSeries(ctx *common.Context, dividendSeriesList, divisorSeriesList sin // divideSeriesLists divides one series list by another series list func divideSeriesLists(ctx *common.Context, dividendSeriesList, divisorSeriesList singlePathSpec) (ts.SeriesList, error) { if len(dividendSeriesList.Values) != len(divisorSeriesList.Values) { - err := errors.NewInvalidParamsError(fmt.Errorf( + err := xerrors.NewInvalidParamsError(fmt.Errorf( "divideSeriesLists both SeriesLists must have exactly the same length")) return ts.NewSeriesList(), err } @@ -310,7 +309,7 @@ func aggregate(ctx *common.Context, series singlePathSpec, fname string) (ts.Ser default: // Median: the movingMedian() method already implemented is returning an series non compatible result. skip support for now. // avg_zero is not implemented, skip support for now unless later identified actual use cases. - return ts.NewSeriesList(), errors.NewInvalidParamsError(fmt.Errorf("invalid func %s", fname)) + return ts.NewSeriesList(), xerrors.NewInvalidParamsError(fmt.Errorf("invalid func %s", fname)) } } @@ -347,7 +346,7 @@ func aggregateWithWildcards( ) (ts.SeriesList, error) { f, fexists := summarizeFuncs[fname] if !fexists { - err := errors.NewInvalidParamsError(fmt.Errorf( + err := xerrors.NewInvalidParamsError(fmt.Errorf( "invalid func %s", fname)) return ts.NewSeriesList(), err } @@ -657,7 +656,7 @@ func applyFnToMetaSeries(ctx *common.Context, series singlePathSpec, metaSeries f, fexists := summarizeFuncs[fname] if !fexists { - return ts.NewSeriesList(), errors.NewInvalidParamsError(fmt.Errorf("invalid func %s", fname)) + return ts.NewSeriesList(), xerrors.NewInvalidParamsError(fmt.Errorf("invalid func %s", fname)) } newSeries := make([]*ts.Series, 0, len(metaSeries)) @@ -699,7 +698,7 @@ func combineSeries(ctx *common.Context, normalized, start, end, millisPerStep, err := common.Normalize(ctx, ts.SeriesList(series)) if err != nil { - err := errors.NewInvalidParamsError(fmt.Errorf("combine series error: %v", err)) + err := xerrors.NewInvalidParamsError(fmt.Errorf("combine series error: %v", err)) return ts.NewSeriesList(), err } @@ -735,14 +734,14 @@ func weightedAverage( for _, series := range input.Values { if step != series.MillisPerStep() { - err := errors.NewInvalidParamsError(fmt.Errorf("different step sizes in input series not supported")) + err := xerrors.NewInvalidParamsError(fmt.Errorf("different step sizes in input series not supported")) return ts.NewSeriesList(), err } } for _, series := range weights.Values { if step != series.MillisPerStep() { - err := errors.NewInvalidParamsError(fmt.Errorf("different step sizes in input series not supported")) + err := xerrors.NewInvalidParamsError(fmt.Errorf("different step sizes in input series not supported")) return ts.NewSeriesList(), err } } diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 9b8f28d05a..e0143fb8b5 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -322,7 +322,8 @@ func timeShift( shift, err := common.ParseInterval(timeShiftS) if err != nil { - return nil, xerrors.NewInvalidParamsError(fmt.Errorf("invalid timeShift parameter %s: %v", timeShiftS, err)) + return nil, xerrors.NewInvalidParamsError( + fmt.Errorf("invalid timeShift parameter %s: %w", timeShiftS, err)) } contextShiftingFn := func(c *common.Context) *common.Context { @@ -2084,7 +2085,8 @@ func randomWalkFunction(ctx *common.Context, name string, step int) (ts.SeriesLi return ts.NewSeriesList(), xerrors.NewInvalidParamsError(fmt.Errorf("non-positive step size %d", step)) } if !ctx.StartTime.Before(ctx.EndTime) { - return ts.NewSeriesList(), xerrors.NewInvalidParamsError(fmt.Errorf("startTime %v is no earlier than endTime %v", ctx.StartTime, ctx.EndTime)) + return ts.NewSeriesList(), xerrors.NewInvalidParamsError( + fmt.Errorf("startTime %v is no earlier than endTime %v", ctx.StartTime, ctx.EndTime)) } r := rand.New(rand.NewSource(time.Now().UnixNano())) millisPerStep := step * millisPerSecond @@ -2430,7 +2432,8 @@ func offsetToZero(ctx *common.Context, seriesList singlePathSpec) (ts.SeriesList // Note: step is measured in seconds. func timeFunction(ctx *common.Context, name string, step int) (ts.SeriesList, error) { if step <= 0 { - return ts.NewSeriesList(), xerrors.NewInvalidParamsError(fmt.Errorf("step must be a positive int but instead is %d", step)) + return ts.NewSeriesList(), xerrors.NewInvalidParamsError( + fmt.Errorf("step must be a positive int but instead is %d", step)) } stepSizeInMilli := step * millisPerSecond @@ -2449,7 +2452,8 @@ func timeFunction(ctx *common.Context, name string, step int) (ts.SeriesList, er // dashed draws the selected metrics with a dotted line with segments of length f. func dashed(_ *common.Context, seriesList singlePathSpec, dashLength float64) (ts.SeriesList, error) { if dashLength <= 0 { - return ts.NewSeriesList(), xerrors.NewInvalidParamsError(fmt.Errorf("expected a positive dashLength but got %f", dashLength)) + return ts.NewSeriesList(), xerrors.NewInvalidParamsError( + fmt.Errorf("expected a positive dashLength but got %f", dashLength)) } results := make([]*ts.Series, len(seriesList.Values)) diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index 5ca2dc4d5c..776261f354 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -2087,6 +2087,7 @@ func TestAsPercentWithSeriesList(t *testing.T) { requireEqual(t, expected, r.Values) } +// nolint: thelper func requireEqual(t *testing.T, expected, results []*ts.Series) { require.Equal(t, len(expected), len(results)) for i := 0; i < len(results); i++ { diff --git a/src/query/graphite/native/expression.go b/src/query/graphite/native/expression.go index 720e33edc3..d3f4b722b8 100644 --- a/src/query/graphite/native/expression.go +++ b/src/query/graphite/native/expression.go @@ -33,7 +33,8 @@ import ( ) var ( - errTopLevelFunctionMustReturnTimeSeries = xerrors.NewInvalidParamsError(errors.New("top-level functions must return timeseries data")) + errTopLevelFunctionMustReturnTimeSeries = xerrors.NewInvalidParamsError( + errors.New("top-level functions must return timeseries data")) ) // An Expression is a metric query expression From b657a515ce0f3a15e1e47bf501dac206c2934eb7 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Wed, 17 Mar 2021 20:23:43 -0400 Subject: [PATCH 10/11] Fix lint --- src/query/graphite/native/aggregation_functions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/graphite/native/aggregation_functions.go b/src/query/graphite/native/aggregation_functions.go index 6d0846182b..b51acf90a2 100644 --- a/src/query/graphite/native/aggregation_functions.go +++ b/src/query/graphite/native/aggregation_functions.go @@ -698,7 +698,7 @@ func combineSeries(ctx *common.Context, normalized, start, end, millisPerStep, err := common.Normalize(ctx, ts.SeriesList(series)) if err != nil { - err := xerrors.NewInvalidParamsError(fmt.Errorf("combine series error: %v", err)) + err := xerrors.NewInvalidParamsError(fmt.Errorf("combine series error: %w", err)) return ts.NewSeriesList(), err } From fc3714d901ae28ec2a311c43dee6607543ee7fe2 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Wed, 17 Mar 2021 20:27:59 -0400 Subject: [PATCH 11/11] Fix merge --- .../graphite/native/builtin_functions.go | 102 ------------------ 1 file changed, 102 deletions(-) diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index ccd286673a..11edc0a695 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -849,108 +849,6 @@ func parseWindowSize(windowSizeValue genericInterface, input singlePathSpec) (wi return windowSize, nil } -// movingAverage calculates the moving average of a metric (or metrics) over a time interval. -func movingAverage(ctx *common.Context, input singlePathSpec, windowSizeValue genericInterface, xFilesFactor float64) (*binaryContextShifter, error) { - if len(input.Values) == 0 { - return nil, nil - } - - widowSize, err := parseWindowSize(windowSizeValue, input) - if err != nil { - return nil, err - } - - contextShiftingFn := func(c *common.Context) *common.Context { - opts := common.NewChildContextOptions() - opts.AdjustTimeRange(0, 0, widowSize.deltaValue, 0) - childCtx := c.NewChildContext(opts) - return childCtx - } - - bootstrapStartTime, bootstrapEndTime := ctx.StartTime.Add(-widowSize.deltaValue), 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] - stepSize := series.MillisPerStep() - windowPoints := widowSize.windowSizeFunc(stepSize) - if windowPoints == 0 { - err := xerrors.NewInvalidParamsError(fmt.Errorf( - "windowSize should not be smaller than stepSize, windowSize=%v, stepSize=%d", - windowSizeValue, stepSize)) - return ts.NewSeriesList(), err - } - - numSteps := series.Len() - offset := bootstrap.Len() - numSteps - vals := ts.NewValues(ctx, series.MillisPerStep(), numSteps) - sum := 0.0 - num := 0 - nans := 0 - firstPoint := false - for i := 0; i < numSteps; i++ { - // NB: skip if the number of points received is less than the number - // of points in the lookback window. - if !firstPoint { - firstPoint = true - for j := offset - windowPoints; j < offset; j++ { - if j < 0 { - continue - } - - v := bootstrap.ValueAt(j) - if !math.IsNaN(v) { - sum += v - num++ - } else { - nans++ - } - } - } else { - if i+offset-windowPoints > 0 { - prev := bootstrap.ValueAt(i + offset - windowPoints - 1) - if !math.IsNaN(prev) { - sum -= prev - num-- - } else { - nans-- - } - } - next := bootstrap.ValueAt(i + offset - 1) - if !math.IsNaN(next) { - sum += next - num++ - } else { - nans++ - } - } - - if nans < windowPoints && effectiveXFF(windowPoints, nans, xFilesFactor) { - vals.SetValueAt(i, sum/float64(num)) - } - } - name := fmt.Sprintf("movingAverage(%s,%s)", series.Name(), widowSize.stringValue) - 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 -} - // exponentialMovingAverage takes a series of values and a window size and produces // an exponential moving average utilizing the following formula: // ema(current) = constant * (Current Value) + (1 - constant) * ema(previous)