stackdriver: load time series meta data for group by dropdown

This commit is contained in:
Erik Sundell 2018-09-13 18:22:48 +02:00 committed by Daniel Lee
parent 5763d3cae2
commit add23d9716
4 changed files with 69 additions and 18 deletions

View File

@ -103,6 +103,7 @@ func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Stackd
params.Add("interval.startTime", startTime.UTC().Format(time.RFC3339)) params.Add("interval.startTime", startTime.UTC().Format(time.RFC3339))
params.Add("interval.endTime", endTime.UTC().Format(time.RFC3339)) params.Add("interval.endTime", endTime.UTC().Format(time.RFC3339))
params.Add("filter", "metric.type=\""+metricType+"\"") params.Add("filter", "metric.type=\""+metricType+"\"")
params.Add("view", query.Model.Get("view").MustString())
setAggParams(&params, query) setAggParams(&params, query)
if setting.Env == setting.DEV { if setting.Env == setting.DEV {

View File

@ -11,17 +11,16 @@ export default class StackdriverDatasource {
this.id = instanceSettings.id; this.id = instanceSettings.id;
} }
async query(options) { async getTimeSeries(options) {
const queries = options.targets.filter(target => !target.hide).map(t => ({ const queries = options.targets.filter(target => !target.hide).map(t => ({
refId: t.refId, refId: t.refId,
datasourceId: this.id, datasourceId: this.id,
metricType: t.metricType, metricType: t.metricType,
primaryAggregation: t.aggregation.crossSeriesReducer, primaryAggregation: 'REDUCE_MEAN', //t.aggregation.crossSeriesReducer,
groupBys: t.aggregation.groupBys, // groupBys: t.aggregation.groupBys,
view: t.view || 'FULL',
})); }));
const result = [];
const { data } = await this.backendSrv.datasourceRequest({ const { data } = await this.backendSrv.datasourceRequest({
url: '/api/tsdb/query', url: '/api/tsdb/query',
method: 'POST', method: 'POST',
@ -31,7 +30,12 @@ export default class StackdriverDatasource {
queries, queries,
}, },
}); });
return data;
}
async query(options) {
const result = [];
const data = await this.getTimeSeries(options);
if (data.results) { if (data.results) {
Object['values'](data.results).forEach(queryRes => { Object['values'](data.results).forEach(queryRes => {
if (!queryRes.series) { if (!queryRes.series) {

View File

@ -2,8 +2,8 @@
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-9">Metric Type</span> <span class="gf-form-label width-9">Metric Type</span>
<gf-form-dropdown model="ctrl.target.metricType" get-options="ctrl.getMetricTypes($query)" class="min-width-20" <gf-form-dropdown model="ctrl.target.metricType" get-options="ctrl.getMetricTypes($query)" class="min-width-20" disabled
disabled type="text" allow-custom="true" lookup-text="true" css-class="min-width-12" on-change="ctrl.refresh()"></gf-form-dropdown> type="text" allow-custom="true" lookup-text="true" css-class="min-width-12" on-change="ctrl.onMetricTypeChange()"></gf-form-dropdown>
</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>
@ -30,8 +30,8 @@
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-9">Project</span> <span class="gf-form-label width-9">Project</span>
<input class="gf-form-input" disabled type="text" ng-model='ctrl.target.project.name' get-options="ctrl.getProjects()" <input class="gf-form-input" disabled type="text" ng-model='ctrl.target.project.name' get-options="ctrl.getProjects()" css-class="min-width-12"
css-class="min-width-12" /> />
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword" ng-click="ctrl.showHelp = !ctrl.showHelp"> <label class="gf-form-label query-keyword" ng-click="ctrl.showHelp = !ctrl.showHelp">
@ -63,4 +63,4 @@ Help text for aliasing
<div class="gf-form" ng-show="ctrl.lastQueryError"> <div class="gf-form" ng-show="ctrl.lastQueryError">
<pre class="gf-form-pre alert alert-error">{{ctrl.lastQueryError}}</pre> <pre class="gf-form-pre alert alert-error">{{ctrl.lastQueryError}}</pre>
</div> </div>
</query-editor-row> </query-editor-row>

View File

@ -2,10 +2,16 @@ import _ from 'lodash';
import { QueryCtrl } from 'app/plugins/sdk'; import { QueryCtrl } from 'app/plugins/sdk';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
export interface LabelType {
key: string;
value: string;
}
export interface QueryMeta { export interface QueryMeta {
rawQuery: string; rawQuery: string;
rawQueryString: string; rawQueryString: string;
metricLabels: any; metricLabels: LabelType[];
resourceLabels: LabelType[];
} }
export class StackdriverQueryCtrl extends QueryCtrl { export class StackdriverQueryCtrl extends QueryCtrl {
static templateUrl = 'partials/query.editor.html'; static templateUrl = 'partials/query.editor.html';
@ -59,18 +65,22 @@ export class StackdriverQueryCtrl extends QueryCtrl {
showLastQuery: boolean; showLastQuery: boolean;
lastQueryMeta: QueryMeta; lastQueryMeta: QueryMeta;
lastQueryError?: string; lastQueryError?: string;
metricLabels: LabelType[];
resourceLabels: LabelType[];
/** @ngInject */ /** @ngInject */
constructor($scope, $injector, private uiSegmentSrv) { constructor($scope, $injector, private uiSegmentSrv, private timeSrv) {
super($scope, $injector); super($scope, $injector);
_.defaultsDeep(this.target, this.defaults); _.defaultsDeep(this.target, this.defaults);
this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope); this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
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))
.then(this.getLabels.bind(this));
this.groupBySegments = _.map(this.target.aggregation.groupBys, groupBy => { this.groupBySegments = this.target.aggregation.groupBys.map(groupBy => {
return uiSegmentSrv.getSegmentForValue(groupBy); return uiSegmentSrv.getSegmentForValue(groupBy);
}); });
this.ensurePlusButton(this.groupBySegments); this.ensurePlusButton(this.groupBySegments);
@ -116,12 +126,47 @@ export class StackdriverQueryCtrl extends QueryCtrl {
} }
} }
getGroupBys() { async getLabels() {
const segments = _.map(Object.keys(this.lastQueryMeta.metricLabels), (label: string) => { const data = await this.datasource.getTimeSeries({
return this.uiSegmentSrv.newSegment({ value: label, expandable: false }); targets: [
{
refId: this.target.refId,
datasourceId: this.datasource.id,
metricType: this.target.metricType,
aggregation: {
crossSeriesReducer: 'REDUCE_NONE',
},
view: 'HEADERS',
},
],
range: this.timeSrv.timeRange(),
}); });
return Promise.resolve(segments); this.metricLabels = data.results[this.target.refId].meta.metricLabels;
this.resourceLabels = data.results[this.target.refId].meta.resourceLabels;
}
async onMetricTypeChange() {
this.refresh();
this.getLabels();
}
getGroupBys() {
const metricLabels = Object.keys(this.metricLabels).map(l => {
return this.uiSegmentSrv.newSegment({
value: `metric.label.${l}`,
expandable: false,
});
});
const resourceLabels = Object.keys(this.resourceLabels).map(l => {
return this.uiSegmentSrv.newSegment({
value: `resource.label.${l}`,
expandable: false,
});
});
return Promise.resolve([...metricLabels, ...resourceLabels]);
} }
groupByChanged(segment, index) { groupByChanged(segment, index) {
@ -136,6 +181,7 @@ export class StackdriverQueryCtrl extends QueryCtrl {
[] []
); );
this.ensurePlusButton(this.groupBySegments); this.ensurePlusButton(this.groupBySegments);
this.refresh();
} }
ensurePlusButton(segments) { ensurePlusButton(segments) {