mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
stackdriver: wip - group bys
This commit is contained in:
parent
c71970baa9
commit
9c8593e71f
@ -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
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
}
|
}
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
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 @@
|
|||||||
</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';
|
|||||||
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 {
|
|||||||
};
|
};
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user