diff --git a/pkg/tsdb/stackdriver/stackdriver.go b/pkg/tsdb/stackdriver/stackdriver.go index b21da2054ea..b69b9eb372e 100644 --- a/pkg/tsdb/stackdriver/stackdriver.go +++ b/pkg/tsdb/stackdriver/stackdriver.go @@ -126,10 +126,17 @@ func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Stackd slog.Debug("Stackdriver request", "params", params) } + groupBys := query.Model.Get("groupBys").MustArray() + groupBysAsStrings := make([]string, 0) + for _, groupBy := range groupBys { + groupBysAsStrings = append(groupBysAsStrings, groupBy.(string)) + } + stackdriverQueries = append(stackdriverQueries, &StackdriverQuery{ - Target: target, - Params: params, - RefID: query.RefId, + Target: target, + Params: params, + RefID: query.RefId, + GroupBys: groupBysAsStrings, }) } @@ -182,7 +189,6 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *Stackdriv } req.URL.RawQuery = query.Params.Encode() - fmt.Println("req.URL.RawQuery: ", req.URL.RawQuery) queryResult.Meta.Set("rawQuery", req.URL.RawQuery) span, ctx := opentracing.StartSpanFromContext(ctx, "stackdriver query") @@ -211,7 +217,7 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *Stackdriv return queryResult, nil } - err = e.parseResponse(queryResult, data) + err = e.parseResponse(queryResult, data, query) if err != nil { queryResult.Error = err return queryResult, nil @@ -242,7 +248,7 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (Stackdriver return data, nil } -func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data StackdriverResponse) error { +func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data StackdriverResponse, query *StackdriverQuery) error { metricLabels := make(map[string][]string) resourceLabels := make(map[string][]string) @@ -260,13 +266,19 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta if !containsLabel(metricLabels[key], value) { metricLabels[key] = append(metricLabels[key], value) } - metricName += " " + value + if len(query.GroupBys) == 0 || containsLabel(query.GroupBys, "metric.label."+key) { + metricName += " " + value + } } for key, value := range series.Resource.Labels { if !containsLabel(resourceLabels[key], value) { resourceLabels[key] = append(resourceLabels[key], value) } + + if containsLabel(query.GroupBys, "resource.label."+key) { + metricName += " " + value + } } queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{ @@ -277,6 +289,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta queryRes.Meta.Set("resourceLabels", resourceLabels) queryRes.Meta.Set("metricLabels", metricLabels) + queryRes.Meta.Set("groupBys", query.GroupBys) return nil } diff --git a/pkg/tsdb/stackdriver/stackdriver_test.go b/pkg/tsdb/stackdriver/stackdriver_test.go index ac5bf5f96e7..8f1a7605e02 100644 --- a/pkg/tsdb/stackdriver/stackdriver_test.go +++ b/pkg/tsdb/stackdriver/stackdriver_test.go @@ -168,16 +168,13 @@ func TestStackdriver(t *testing.T) { Convey("Parse stackdriver response in the time series format", func() { Convey("when data from query aggregated to one time series", func() { - var data StackdriverResponse - - jsonBody, err := ioutil.ReadFile("./test-data/1-series-response-agg-one-metric.json") - So(err, ShouldBeNil) - err = json.Unmarshal(jsonBody, &data) + data, err := loadTestFile("./test-data/1-series-response-agg-one-metric.json") So(err, ShouldBeNil) So(len(data.TimeSeries), ShouldEqual, 1) res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"} - err = executor.parseResponse(res, data) + query := &StackdriverQuery{} + err = executor.parseResponse(res, data, query) So(err, ShouldBeNil) So(len(res.Series), ShouldEqual, 1) @@ -197,16 +194,13 @@ func TestStackdriver(t *testing.T) { }) Convey("when data from query with no aggregation", func() { - var data StackdriverResponse - - jsonBody, err := ioutil.ReadFile("./test-data/2-series-response-no-agg.json") - So(err, ShouldBeNil) - err = json.Unmarshal(jsonBody, &data) + data, err := loadTestFile("./test-data/2-series-response-no-agg.json") So(err, ShouldBeNil) So(len(data.TimeSeries), ShouldEqual, 3) res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"} - err = executor.parseResponse(res, data) + query := &StackdriverQuery{} + err = executor.parseResponse(res, data, query) So(err, ShouldBeNil) Convey("Should add labels to metric name", func() { @@ -214,7 +208,9 @@ func TestStackdriver(t *testing.T) { So(res.Series[0].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-asia-east-1") So(res.Series[1].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-europe-west-1") So(res.Series[2].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-us-east-1") + }) + Convey("Should parse to time series", func() { So(len(res.Series[0].Points), ShouldEqual, 3) So(res.Series[0].Points[0][0].Float64, ShouldEqual, 9.8566497180145) So(res.Series[0].Points[1][0].Float64, ShouldEqual, 9.7323568146676) @@ -240,6 +236,38 @@ func TestStackdriver(t *testing.T) { So(resourceLabels["project_id"][0], ShouldEqual, "grafana-prod") }) }) + + Convey("when data from query with no aggregation and group bys", func() { + data, err := loadTestFile("./test-data/2-series-response-no-agg.json") + So(err, ShouldBeNil) + So(len(data.TimeSeries), ShouldEqual, 3) + + res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"} + query := &StackdriverQuery{GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}} + err = executor.parseResponse(res, data, query) + So(err, ShouldBeNil) + + Convey("Should add instance name and zone labels to metric name", func() { + So(len(res.Series), ShouldEqual, 3) + So(res.Series[0].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-asia-east-1 asia-east1-a") + So(res.Series[1].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-europe-west-1 europe-west1-b") + So(res.Series[2].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-us-east-1 us-east1-b") + }) + }) }) }) } + +func loadTestFile(path string) (StackdriverResponse, error) { + var data StackdriverResponse + + jsonBody, err := ioutil.ReadFile(path) + if err != nil { + return data, err + } + err = json.Unmarshal(jsonBody, &data) + if err != nil { + return data, err + } + return data, nil +} diff --git a/pkg/tsdb/stackdriver/types.go b/pkg/tsdb/stackdriver/types.go index b64dbceea36..88a2abd8548 100644 --- a/pkg/tsdb/stackdriver/types.go +++ b/pkg/tsdb/stackdriver/types.go @@ -6,9 +6,10 @@ import ( ) type StackdriverQuery struct { - Target string - Params url.Values - RefID string + Target string + Params url.Values + RefID string + GroupBys []string } type StackdriverResponse struct {