diff --git a/decoder/target.go b/decoder/target.go index cf905f7d..9bec5f5e 100644 --- a/decoder/target.go +++ b/decoder/target.go @@ -13,6 +13,7 @@ import ( var ErrTargetNotConfigured = fmt.Errorf("target not configured") var ErrInvalidStackdriverType = fmt.Errorf("invalid stackdriver target type") var ErrInvalidStackdriverAggregation = fmt.Errorf("invalid stackdriver aggregation type") +var ErrInvalidStackdriverPreprocessor = fmt.Errorf("invalid stackdriver preprocessor") var ErrInvalidStackdriverAlignment = fmt.Errorf("invalid stackdriver alignment method") type Target struct { @@ -118,16 +119,17 @@ func (t InfluxDBTarget) toOptions() []influxdb.Option { } type StackdriverTarget struct { - Project string - Type string - Metric string - Filters StackdriverFilters `yaml:",omitempty"` - Aggregation string `yaml:",omitempty"` - Alignment *StackdriverAlignment `yaml:",omitempty"` - Legend string `yaml:",omitempty"` - Ref string `yaml:",omitempty"` - Hidden bool `yaml:",omitempty"` - GroupBy []string `yaml:"group_by,omitempty"` + Project string + Type string + Metric string + Filters StackdriverFilters `yaml:",omitempty"` + Aggregation string `yaml:",omitempty"` + Alignment *StackdriverAlignment `yaml:",omitempty"` + Legend string `yaml:",omitempty"` + Preprocessor string `yaml:",omitempty"` + Ref string `yaml:",omitempty"` + Hidden bool `yaml:",omitempty"` + GroupBy []string `yaml:"group_by,omitempty"` } type StackdriverFilters struct { @@ -192,6 +194,15 @@ func (t StackdriverTarget) toOptions() ([]stackdriver.Option, error) { opts = append(opts, opt) } + if t.Preprocessor != "" { + opt, err := t.preprocessor() + if err != nil { + return nil, err + } + + opts = append(opts, opt) + } + if t.Alignment != nil { opt, err := t.Alignment.toOption() if err != nil { @@ -239,6 +250,17 @@ func (t StackdriverTarget) aggregation() (stackdriver.Option, error) { } } +func (t StackdriverTarget) preprocessor() (stackdriver.Option, error) { + switch t.Preprocessor { + case "delta": + return stackdriver.Preprocessor(stackdriver.PreprocessDelta), nil + case "rate": + return stackdriver.Preprocessor(stackdriver.PreprocessRate), nil + default: + return nil, ErrInvalidStackdriverPreprocessor + } +} + func (filters StackdriverFilters) toOptions() []stackdriver.FilterOption { opts := []stackdriver.FilterOption{} diff --git a/decoder/target_test.go b/decoder/target_test.go index 6a2893a8..a1a4f747 100644 --- a/decoder/target_test.go +++ b/decoder/target_test.go @@ -98,6 +98,44 @@ func TestValidStackdriverAggregations(t *testing.T) { } } +func TestValidStackdriverPreprocessor(t *testing.T) { + testCases := []struct { + input string + expected stackdriver.Reducer + }{ + {input: "delta", expected: stackdriver.PreprocessDelta}, + {input: "rate", expected: stackdriver.PreprocessRate}, + } + + for _, testCase := range testCases { + tc := testCase + + t.Run(tc.input, func(t *testing.T) { + req := require.New(t) + + panel := StackdriverTarget{Preprocessor: tc.input} + + opt, err := panel.preprocessor() + + req.NoError(err) + + target := stackdriver.Delta("test") + opt(target) + + req.Equal(string(tc.expected), target.Builder.Preprocessor) + }) + } +} + +func TestInvalidStackdriverPreprocessor(t *testing.T) { + req := require.New(t) + + _, err := StackdriverTarget{Preprocessor: "invalid"}.toTarget() + + req.Error(err) + req.Equal(ErrInvalidStackdriverPreprocessor, err) +} + func TestValidStackdriverTargetTypes(t *testing.T) { testCases := []struct { input string diff --git a/go.mod b/go.mod index 0f64a5cb..abbf7bf0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/K-Phoen/grabana go 1.16 require ( - github.com/K-Phoen/sdk v0.8.3 + github.com/K-Phoen/sdk v0.8.4 github.com/blang/semver v3.5.1+incompatible github.com/gosimple/slug v1.12.0 // indirect github.com/prometheus/common v0.32.0 diff --git a/go.sum b/go.sum index cb36a2ff..a005af2f 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/K-Phoen/sdk v0.8.3 h1:UZU6UfWlIBkMH8rx/qUgTxcEYLtGyh49xvjJFePrVyI= -github.com/K-Phoen/sdk v0.8.3/go.mod h1:fnbOsbRksULSfcXjOI6W1/HISz5o/u1iEhF/fLedqTg= +github.com/K-Phoen/sdk v0.8.4 h1:KAH0ipC/4iWxslFudjy84Gm8fkaVRfekZK+BPAvoF30= +github.com/K-Phoen/sdk v0.8.4/go.mod h1:fnbOsbRksULSfcXjOI6W1/HISz5o/u1iEhF/fLedqTg= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= diff --git a/target/stackdriver/stackdriver.go b/target/stackdriver/stackdriver.go index 6ec5b87f..da97a247 100644 --- a/target/stackdriver/stackdriver.go +++ b/target/stackdriver/stackdriver.go @@ -8,6 +8,12 @@ type Option func(target *Stackdriver) const AlignmentStackdriverAuto = "stackdriver-auto" const AlignmentGrafanaAuto = "grafana-auto" +// PreprocessorMethod defines the available pre-processing options. +type PreprocessorMethod string + +const PreprocessRate = "rate" +const PreprocessDelta = "delta" + // Aligner specifies the operation that will be applied to the data points in // each alignment period in a time series. // See https://cloud.google.com/monitoring/api/ref_v3/rest/v3/projects.alertPolicies#Aligner @@ -148,6 +154,13 @@ func Alignment(aligner Aligner, alignmentPeriod string) Option { } } +// Preprocessor defines how the time series should be pre-processed. +func Preprocessor(preprocessor PreprocessorMethod) Option { + return func(stackdriver *Stackdriver) { + stackdriver.Builder.Preprocessor = string(preprocessor) + } +} + // Filter allows to specify which time series will be in the results. func Filter(filters ...FilterOption) Option { return func(stackdriver *Stackdriver) { diff --git a/target/stackdriver/stackdriver_test.go b/target/stackdriver/stackdriver_test.go index e7eff511..59a9c701 100644 --- a/target/stackdriver/stackdriver_test.go +++ b/target/stackdriver/stackdriver_test.go @@ -198,3 +198,17 @@ func TestTargetSupportsGroupBys(t *testing.T) { req.ElementsMatch(target.Builder.GroupBys, []string{"field", "other"}) } + +func TestPreprocessorCanBeConfigured(t *testing.T) { + req := require.New(t) + preprocessors := []stackdriver.PreprocessorMethod{ + stackdriver.PreprocessDelta, + stackdriver.PreprocessRate, + } + + for _, preprocessor := range preprocessors { + target := stackdriver.Delta("", stackdriver.Preprocessor(preprocessor)) + + req.Equal(string(preprocessor), target.Builder.Preprocessor) + } +} diff --git a/vendor/github.com/K-Phoen/sdk/panel.go b/vendor/github.com/K-Phoen/sdk/panel.go index cffc301c..5af303f9 100644 --- a/vendor/github.com/K-Phoen/sdk/panel.go +++ b/vendor/github.com/K-Phoen/sdk/panel.go @@ -648,6 +648,7 @@ type Target struct { CrossSeriesReducer string `json:"crossSeriesReducer,omitempty"` PerSeriesAligner string `json:"perSeriesAligner,omitempty"` ValueType string `json:"valueType,omitempty"` + Preprocessor string `json:"preprocessor,omitempty"` GroupBys []string `json:"groupBys,omitempty"` Tags []struct { Key string `json:"key,omitempty"` diff --git a/vendor/modules.txt b/vendor/modules.txt index 5e96c723..9a4dcaf1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/K-Phoen/sdk v0.8.3 +# github.com/K-Phoen/sdk v0.8.4 ## explicit github.com/K-Phoen/sdk # github.com/blang/semver v3.5.1+incompatible