Commit 9c8593e7 by Daniel Lee

stackdriver: wip - group bys

parent c71970ba
...@@ -133,6 +133,12 @@ func setAggParams(params *url.Values, query *tsdb.Query) { ...@@ -133,6 +133,12 @@ func setAggParams(params *url.Values, query *tsdb.Query) {
params.Add("aggregation.alignmentPeriod", "+60s") params.Add("aggregation.alignmentPeriod", "+60s")
} }
groupBys := query.Model.Get("groupBys").MustArray()
if len(groupBys) > 0 {
for i := 0; i < len(groupBys); i++ {
params.Add("aggregation.groupByFields", groupBys[i].(string))
}
}
} }
func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *StackdriverQuery, tsdbQuery *tsdb.TsdbQuery) (*tsdb.QueryResult, error) { func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *StackdriverQuery, tsdbQuery *tsdb.TsdbQuery) (*tsdb.QueryResult, error) {
...@@ -205,6 +211,9 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (StackDriver ...@@ -205,6 +211,9 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (StackDriver
} }
func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data StackDriverResponse) error { func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data StackDriverResponse) error {
metricLabels := make(map[string][]string)
// resourceLabels := make(map[string][]string)
for _, series := range data.TimeSeries { for _, series := range data.TimeSeries {
points := make([]tsdb.TimePoint, 0) points := make([]tsdb.TimePoint, 0)
...@@ -215,15 +224,21 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta ...@@ -215,15 +224,21 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta
} }
metricName := series.Metric.Type metricName := series.Metric.Type
for _, value := range series.Metric.Labels { for key, value := range series.Metric.Labels {
metricLabels[key] = append(metricLabels[key], value)
metricName += " " + value metricName += " " + value
} }
// queryRes.Meta.Set("resourceLabels", series.Resource.Labels)
queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{ queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{
Name: metricName, Name: metricName,
Points: points, Points: points,
}) })
} }
queryRes.Meta.Set("metricLabels", metricLabels)
return nil return nil
} }
......
...@@ -71,6 +71,29 @@ func TestStackdriver(t *testing.T) { ...@@ -71,6 +71,29 @@ func TestStackdriver(t *testing.T) {
So(queries[0].Params["filter"][0], ShouldEqual, "metric.type=\"a/metric/type\"") So(queries[0].Params["filter"][0], ShouldEqual, "metric.type=\"a/metric/type\"")
}) })
Convey("and query has group bys", func() {
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
"target": "target",
"metricType": "a/metric/type",
"primaryAggregation": "REDUCE_NONE",
"groupBys": []interface{}{"metric.label.group1", "metric.label.group2"},
})
queries, err := executor.buildQueries(tsdbQuery)
So(err, ShouldBeNil)
So(len(queries), ShouldEqual, 1)
So(queries[0].RefID, ShouldEqual, "A")
So(queries[0].Target, ShouldEqual, "target")
So(len(queries[0].Params), ShouldEqual, 5)
So(queries[0].Params["interval.startTime"][0], ShouldEqual, "2018-03-15T13:00:00Z")
So(queries[0].Params["interval.endTime"][0], ShouldEqual, "2018-03-15T13:34:00Z")
So(queries[0].Params["aggregation.perSeriesAligner"][0], ShouldEqual, "ALIGN_NONE")
So(queries[0].Params["aggregation.groupByFields"][0], ShouldEqual, "metric.label.group1")
So(queries[0].Params["aggregation.groupByFields"][1], ShouldEqual, "metric.label.group2")
So(queries[0].Params["filter"][0], ShouldEqual, "metric.type=\"a/metric/type\"")
})
}) })
Convey("Parse stackdriver response in the time series format", func() { Convey("Parse stackdriver response in the time series format", func() {
...@@ -127,6 +150,11 @@ func TestStackdriver(t *testing.T) { ...@@ -127,6 +150,11 @@ func TestStackdriver(t *testing.T) {
So(res.Series[0].Points[1][0].Float64, ShouldEqual, 9.7323568146676) So(res.Series[0].Points[1][0].Float64, ShouldEqual, 9.7323568146676)
So(res.Series[0].Points[2][0].Float64, ShouldEqual, 9.7730520330369) So(res.Series[0].Points[2][0].Float64, ShouldEqual, 9.7730520330369)
}) })
Convey("Should add meta for labels to the response", func() {
instanceName := res.Meta.Get("metricLabels").MustMap()["instance_name"]
So(instanceName, ShouldNotBeNil)
})
}) })
}) })
}) })
......
...@@ -16,7 +16,8 @@ export default class StackdriverDatasource { ...@@ -16,7 +16,8 @@ export default class StackdriverDatasource {
refId: t.refId, refId: t.refId,
datasourceId: this.id, datasourceId: this.id,
metricType: t.metricType, metricType: t.metricType,
primaryAggregation: t.aggregation, primaryAggregation: t.aggregation.crossSeriesReducer,
groupBys: t.aggregation.groupBys,
})); }));
const result = []; const result = [];
......
...@@ -10,13 +10,18 @@ ...@@ -10,13 +10,18 @@
</div> </div>
</div> </div>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form gf-form--grow"> <div class="gf-form">
<label class="gf-form-label query-keyword width-9">Aggregation</label> <label class="gf-form-label query-keyword width-9">Aggregation</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent"> <div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input width-11" ng-model="ctrl.target.aggregation" ng-options="f.value as f.text for f in ctrl.aggOptions" <select class="gf-form-input width-11" ng-model="ctrl.target.aggregation.crossSeriesReducer" ng-options="f.value as f.text for f in ctrl.aggOptions"
ng-change="ctrl.refresh()"></select> ng-change="ctrl.refresh()"></select>
</div> </div>
<div class="gf-form-label gf-form-label--grow"></div> </div>
<div class="gf-form">
<span class="gf-form-label query-keyword width-9">Group By</span>
<div class="gf-form" ng-repeat="segment in ctrl.groupBySegments">
<metric-segment segment="segment" get-options="ctrl.getGroupBys(segment, $index)" on-change="ctrl.groupByChanged(segment, $index)"></metric-segment>
</div>
</div> </div>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
......
...@@ -5,6 +5,7 @@ import appEvents from 'app/core/app_events'; ...@@ -5,6 +5,7 @@ import appEvents from 'app/core/app_events';
export interface QueryMeta { export interface QueryMeta {
rawQuery: string; rawQuery: string;
rawQueryString: string; rawQueryString: string;
metricLabels: any;
} }
export class StackdriverQueryCtrl extends QueryCtrl { export class StackdriverQueryCtrl extends QueryCtrl {
static templateUrl = 'partials/query.editor.html'; static templateUrl = 'partials/query.editor.html';
...@@ -15,6 +16,12 @@ export class StackdriverQueryCtrl extends QueryCtrl { ...@@ -15,6 +16,12 @@ export class StackdriverQueryCtrl extends QueryCtrl {
}; };
metricType: string; metricType: string;
refId: string; refId: string;
aggregation: {
crossSeriesReducer: string;
alignmentPeriod: string;
perSeriesAligner: string;
groupBys: string[];
};
}; };
defaultDropdownValue = 'Select metric'; defaultDropdownValue = 'Select metric';
...@@ -24,9 +31,16 @@ export class StackdriverQueryCtrl extends QueryCtrl { ...@@ -24,9 +31,16 @@ export class StackdriverQueryCtrl extends QueryCtrl {
name: 'loading project...', name: 'loading project...',
}, },
metricType: this.defaultDropdownValue, metricType: this.defaultDropdownValue,
aggregation: 'REDUCE_MEAN', aggregation: {
crossSeriesReducer: 'REDUCE_MEAN',
alignmentPeriod: '',
perSeriesAligner: '',
groupBys: [],
},
}; };
groupBySegments: any[];
aggOptions = [ aggOptions = [
{ text: 'none', value: 'REDUCE_NONE' }, { text: 'none', value: 'REDUCE_NONE' },
{ text: 'mean', value: 'REDUCE_MEAN' }, { text: 'mean', value: 'REDUCE_MEAN' },
...@@ -47,7 +61,7 @@ export class StackdriverQueryCtrl extends QueryCtrl { ...@@ -47,7 +61,7 @@ export class StackdriverQueryCtrl extends QueryCtrl {
lastQueryError?: string; lastQueryError?: string;
/** @ngInject */ /** @ngInject */
constructor($scope, $injector) { constructor($scope, $injector, private uiSegmentSrv) {
super($scope, $injector); super($scope, $injector);
_.defaultsDeep(this.target, this.defaults); _.defaultsDeep(this.target, this.defaults);
...@@ -55,6 +69,11 @@ export class StackdriverQueryCtrl extends QueryCtrl { ...@@ -55,6 +69,11 @@ export class StackdriverQueryCtrl extends QueryCtrl {
this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope); this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
this.getCurrentProject().then(this.getMetricTypes.bind(this)); this.getCurrentProject().then(this.getMetricTypes.bind(this));
this.groupBySegments = _.map(this.target.aggregation.groupBys, groupBy => {
return uiSegmentSrv.getSegmentForValue(groupBy);
});
this.ensurePlusButton(this.groupBySegments);
} }
async getCurrentProject() { async getCurrentProject() {
...@@ -97,6 +116,37 @@ export class StackdriverQueryCtrl extends QueryCtrl { ...@@ -97,6 +116,37 @@ export class StackdriverQueryCtrl extends QueryCtrl {
} }
} }
getGroupBys() {
const segments = _.map(Object.keys(this.lastQueryMeta.metricLabels), (label: string) => {
return this.uiSegmentSrv.newSegment({ value: label, expandable: false });
});
return Promise.resolve(segments);
}
groupByChanged(segment, index) {
this.target.aggregation.groupBys = _.reduce(
this.groupBySegments,
function(memo, seg) {
if (!seg.fake) {
memo.push(seg.value);
}
return memo;
},
[]
);
this.ensurePlusButton(this.groupBySegments);
}
ensurePlusButton(segments) {
const count = segments.length;
const lastSegment = segments[Math.max(count - 1, 0)];
if (!lastSegment || lastSegment.type !== 'plus-button') {
segments.push(this.uiSegmentSrv.newPlusButton());
}
}
onDataReceived(dataList) { onDataReceived(dataList) {
this.lastQueryError = null; this.lastQueryError = null;
this.lastQueryMeta = null; this.lastQueryMeta = null;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment