mirror of
https://github.com/grafana/grafana.git
synced 2025-08-06 20:59:35 +08:00
stackdriver: better error handling and show query metadata
If the Stackdriver returns an error, show that error in the query editor. Also, allow the user to see the raw querystring that was sent to google (for troubleshooting).
This commit is contained in:
@ -20,26 +20,27 @@ export default class StackdriverDatasource {
|
||||
|
||||
const result = [];
|
||||
|
||||
try {
|
||||
const { data } = await this.backendSrv.datasourceRequest({
|
||||
url: '/api/tsdb/query',
|
||||
method: 'POST',
|
||||
data: {
|
||||
from: options.range.from.valueOf().toString(),
|
||||
to: options.range.to.valueOf().toString(),
|
||||
queries,
|
||||
},
|
||||
});
|
||||
const { data } = await this.backendSrv.datasourceRequest({
|
||||
url: '/api/tsdb/query',
|
||||
method: 'POST',
|
||||
data: {
|
||||
from: options.range.from.valueOf().toString(),
|
||||
to: options.range.to.valueOf().toString(),
|
||||
queries,
|
||||
},
|
||||
});
|
||||
|
||||
if (data.results) {
|
||||
Object['values'](data.results).forEach(queryRes => {
|
||||
queryRes.series.forEach(series => {
|
||||
result.push({ target: series.name, datapoints: series.points });
|
||||
if (data.results) {
|
||||
Object['values'](data.results).forEach(queryRes => {
|
||||
queryRes.series.forEach(series => {
|
||||
result.push({
|
||||
target: series.name,
|
||||
datapoints: series.points,
|
||||
refId: queryRes.refId,
|
||||
meta: queryRes.meta,
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
return { data: result };
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
@ -2,15 +2,49 @@
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<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()" css-class="min-width-12"
|
||||
/>
|
||||
<input class="gf-form-input" disabled type="text" ng-model='ctrl.target.project.name' get-options="ctrl.getProjects()"
|
||||
css-class="min-width-12" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">Metric Type</span>
|
||||
<gf-form-dropdown model="ctrl.target.metricType" get-options="ctrl.getMetricTypes($query)" class="gf-form-input" disabled
|
||||
type="text" allow-custom="true" lookup-text="true" css-class="min-width-12" on-change="ctrl.refresh()"></gf-form-dropdown>
|
||||
<gf-form-dropdown model="ctrl.target.metricType" get-options="ctrl.getMetricTypes($query)" class="min-width-20"
|
||||
disabled type="text" allow-custom="true" lookup-text="true" css-class="min-width-12" on-change="ctrl.refresh()"></gf-form-dropdown>
|
||||
</div>
|
||||
<div class="gf-form gf-form--grow">
|
||||
<div class="gf-form-label gf-form-label--grow"></div>
|
||||
</div>
|
||||
</div>
|
||||
</query-editor-row>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label query-keyword" ng-click="ctrl.showHelp = !ctrl.showHelp">
|
||||
Show Help
|
||||
<i class="fa fa-caret-down" ng-show="ctrl.showHelp"></i>
|
||||
<i class="fa fa-caret-right" ng-hide="ctrl.showHelp"></i>
|
||||
</label>
|
||||
</div>
|
||||
<div class="gf-form" ng-show="ctrl.lastQueryMeta">
|
||||
<label class="gf-form-label query-keyword" ng-click="ctrl.showLastQuery = !ctrl.showLastQuery">
|
||||
Raw Query
|
||||
<i class="fa fa-caret-down" ng-show="ctrl.showLastQuery"></i>
|
||||
<i class="fa fa-caret-right" ng-hide="ctrl.showLastQuery"></i>
|
||||
</label>
|
||||
</div>
|
||||
<div class="gf-form gf-form--grow">
|
||||
<div class="gf-form-label gf-form-label--grow"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.showLastQuery">
|
||||
<pre class="gf-form-pre">{{ctrl.lastQueryMeta.rawQueryString}}</pre>
|
||||
</div>
|
||||
<div class="gf-form" ng-show="ctrl.showHelp">
|
||||
<pre class="gf-form-pre alert alert-info">
|
||||
Help text for aliasing
|
||||
</pre>
|
||||
</div>
|
||||
<div class="gf-form" ng-show="ctrl.lastQueryError">
|
||||
<pre class="gf-form-pre alert alert-error">{{ctrl.lastQueryError}}</pre>
|
||||
</div>
|
||||
</query-editor-row>
|
||||
|
@ -3,15 +3,23 @@
|
||||
"type": "datasource",
|
||||
"id": "stackdriver",
|
||||
"metrics": true,
|
||||
"alerting": false,
|
||||
"alerting": true,
|
||||
"annotations": false,
|
||||
"queryOptions": {
|
||||
"maxDataPoints": true,
|
||||
"cacheTimeout": true
|
||||
},
|
||||
"info": {
|
||||
"description": "Data Source for Stackdriver",
|
||||
"version": "1.0.0"
|
||||
"description": "Google Stackdriver Datasource for Grafana",
|
||||
"version": "1.0.0",
|
||||
"logos": {
|
||||
"small": "img/stackdriver_logo.png",
|
||||
"large": "img/stackdriver_logo.png"
|
||||
},
|
||||
"author": {
|
||||
"name": "Grafana Project",
|
||||
"url": "https://grafana.com"
|
||||
}
|
||||
},
|
||||
"routes": [
|
||||
{
|
||||
|
@ -2,6 +2,10 @@ import _ from 'lodash';
|
||||
import { QueryCtrl } from 'app/plugins/sdk';
|
||||
import appEvents from 'app/core/app_events';
|
||||
|
||||
export interface QueryMeta {
|
||||
rawQuery: string;
|
||||
rawQueryString: string;
|
||||
}
|
||||
export class StackdriverQueryCtrl extends QueryCtrl {
|
||||
static templateUrl = 'partials/query.editor.html';
|
||||
target: {
|
||||
@ -10,21 +14,31 @@ export class StackdriverQueryCtrl extends QueryCtrl {
|
||||
name: string;
|
||||
};
|
||||
metricType: string;
|
||||
refId: string;
|
||||
};
|
||||
defaultDropdownValue = 'select';
|
||||
defaultDropdownValue = 'Select metric';
|
||||
|
||||
defaults = {
|
||||
project: {
|
||||
id: 'default',
|
||||
name: 'loading project...',
|
||||
},
|
||||
metricType: this.defaultDropdownValue,
|
||||
// metricType: this.defaultDropdownValue,
|
||||
};
|
||||
|
||||
showHelp: boolean;
|
||||
showLastQuery: boolean;
|
||||
lastQueryMeta: QueryMeta;
|
||||
lastQueryError?: string;
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope, $injector) {
|
||||
super($scope, $injector);
|
||||
_.defaultsDeep(this.target, this.defaults);
|
||||
|
||||
this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
|
||||
this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
|
||||
|
||||
this.getCurrentProject().then(this.getMetricTypes.bind(this));
|
||||
}
|
||||
|
||||
@ -67,4 +81,34 @@ export class StackdriverQueryCtrl extends QueryCtrl {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
onDataReceived(dataList) {
|
||||
this.lastQueryError = null;
|
||||
this.lastQueryMeta = null;
|
||||
|
||||
const anySeriesFromQuery: any = _.find(dataList, { refId: this.target.refId });
|
||||
if (anySeriesFromQuery) {
|
||||
this.lastQueryMeta = anySeriesFromQuery.meta;
|
||||
this.lastQueryMeta.rawQueryString = decodeURIComponent(this.lastQueryMeta.rawQuery);
|
||||
}
|
||||
}
|
||||
|
||||
onDataError(err) {
|
||||
if (err.data && err.data.results) {
|
||||
const queryRes = err.data.results[this.target.refId];
|
||||
if (queryRes) {
|
||||
this.lastQueryMeta = queryRes.meta;
|
||||
this.lastQueryMeta.rawQueryString = decodeURIComponent(this.lastQueryMeta.rawQuery);
|
||||
|
||||
let jsonBody;
|
||||
try {
|
||||
jsonBody = JSON.parse(queryRes.error);
|
||||
} catch {
|
||||
this.lastQueryError = queryRes.error;
|
||||
}
|
||||
|
||||
this.lastQueryError = jsonBody.error.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user