mysql: worked on mysql data soruce

This commit is contained in:
Torkel Ödegaard 2017-04-20 17:10:09 +02:00
parent 1bbc149089
commit c78c460f79
10 changed files with 114 additions and 39 deletions

View File

@ -10,3 +10,5 @@ mysql:
volumes: volumes:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro - /etc/timezone:/etc/timezone:ro
command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all]

View File

@ -50,13 +50,16 @@ func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response {
return ApiError(500, "Metric request error", err) return ApiError(500, "Metric request error", err)
} }
statusCode := 200
for _, res := range resp.Results { for _, res := range resp.Results {
if res.Error != nil { if res.Error != nil {
res.ErrorString = res.Error.Error() res.ErrorString = res.Error.Error()
resp.Message = res.ErrorString
statusCode = 500
} }
} }
return Json(200, &resp) return Json(statusCode, &resp)
} }
// GET /api/tsdb/testdata/scenarios // GET /api/tsdb/testdata/scenarios

View File

@ -27,6 +27,7 @@ type Request struct {
type Response struct { type Response struct {
BatchTimings []*BatchTiming `json:"timings"` BatchTimings []*BatchTiming `json:"timings"`
Results map[string]*QueryResult `json:"results"` Results map[string]*QueryResult `json:"results"`
Message string `json:"message,omitempty"`
} }
type BatchTiming struct { type BatchTiming struct {

View File

@ -112,14 +112,18 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co
defer rows.Close() defer rows.Close()
res, err := e.TransformToTimeSeries(query, rows) format := query.Model.Get("format").MustString("time_series")
if err != nil {
queryResult.Error = err
return result
}
queryResult.Series = res if format == "time_series" {
queryResult.Meta.Set("rowCount", countPointsInAllSeries(res)) res, err := e.TransformToTimeSeries(query, rows)
if err != nil {
queryResult.Error = err
return result
}
queryResult.Series = res
queryResult.Meta.Set("rowCount", countPointsInAllSeries(res))
}
} }
return result return result

View File

@ -184,8 +184,8 @@ class TimeSrv {
timeRangeForUrl() { timeRangeForUrl() {
var range = this.timeRange().raw; var range = this.timeRange().raw;
if (moment.isMoment(range.from)) { range.from = range.from.valueOf(); } if (moment.isMoment(range.from)) { range.from = range.from.valueOf().toString(); }
if (moment.isMoment(range.to)) { range.to = range.to.valueOf(); } if (moment.isMoment(range.to)) { range.to = range.to.valueOf().toString(); }
return range; return range;
} }

View File

@ -106,6 +106,16 @@ class MetricsPanelCtrl extends PanelCtrl {
this.loading = false; this.loading = false;
this.error = err.message || "Request Error"; this.error = err.message || "Request Error";
this.inspector = {error: err}; this.inspector = {error: err};
if (err.data) {
if (err.data.message) {
this.error = err.data.message;
}
if (err.data.error) {
this.error = err.data.error;
}
}
this.events.emit('data-error', err); this.events.emit('data-error', err);
console.log('Panel data error:', err); console.log('Panel data error:', err);
}); });

View File

@ -1,7 +1,7 @@
<div class="gf-form-query"> <div class="gf-form-query">
<div class="gf-form"> <div class="gf-form gf-form-query-letter-cell">
<label class="gf-form-label gf-form-query-letter-cell"> <label class="gf-form-label">
<a class="pointer" tabindex="1" ng-click="ctrl.toggleCollapse()"> <a class="pointer" tabindex="1" ng-click="ctrl.toggleCollapse()">
<span ng-class="{muted: !ctrl.canCollapse}" class="gf-form-query-letter-cell-carret"> <span ng-class="{muted: !ctrl.canCollapse}" class="gf-form-query-letter-cell-carret">
<i class="fa fa-caret-down" ng-hide="ctrl.collapsed"></i> <i class="fa fa-caret-down" ng-hide="ctrl.collapsed"></i>

View File

@ -22,6 +22,7 @@ export class MysqlDatasource {
maxDataPoints: options.maxDataPoints, maxDataPoints: options.maxDataPoints,
datasourceId: this.id, datasourceId: this.id,
rawSql: item.rawSql, rawSql: item.rawSql,
format: item.format,
}; };
}); });
@ -29,29 +30,31 @@ export class MysqlDatasource {
return this.$q.when({data: []}); return this.$q.when({data: []});
} }
return this.backendSrv.post('/api/tsdb/query', { return this.backendSrv.datasourceRequest({
from: options.range.from.valueOf().toString(), url: '/api/tsdb/query',
to: options.range.to.valueOf().toString(), method: 'POST',
queries: queries, data: {
}).then(res => { from: options.range.from.valueOf().toString(),
console.log('mysql response', res); to: options.range.to.valueOf().toString(),
queries: queries,
var data = [];
if (res.results) {
_.forEach(res.results, queryRes => {
if (queryRes.error) {
throw {error: queryRes.error, message: queryRes.error};
}
for (let series of queryRes.series) {
data.push({
target: series.name,
datapoints: series.points
});
}
});
} }
}).then(res => {
var data = [];
if (!res.data.results) {
return {data: data};
}
_.forEach(res.data.results, queryRes => {
for (let series of queryRes.series) {
data.push({
target: series.name,
datapoints: series.points,
refId: queryRes.refId,
meta: queryRes.meta,
});
}
});
return {data: data}; return {data: data};
}); });

View File

@ -1,25 +1,61 @@
///<reference path="../../../headers/common.d.ts" /> ///<reference path="../../../headers/common.d.ts" />
import angular from 'angular'; import angular from 'angular';
import _ from 'lodash';
import {MysqlDatasource} from './datasource'; import {MysqlDatasource} from './datasource';
import {QueryCtrl} from 'app/plugins/sdk'; import {QueryCtrl} from 'app/plugins/sdk';
export interface MysqlQuery {
refId: string;
format: string;
alias: string;
}
export interface QueryMeta {
sql: string;
}
class MysqlQueryCtrl extends QueryCtrl { class MysqlQueryCtrl extends QueryCtrl {
static templateUrl = 'partials/query.editor.html'; static templateUrl = 'partials/query.editor.html';
resultFormats: any; showLastQuerySQL: boolean;
target: any; formats: any[];
target: MysqlQuery;
lastQueryMeta: QueryMeta;
lastQueryError: string;
constructor($scope, $injector) { constructor($scope, $injector) {
super($scope, $injector); super($scope, $injector);
this.target.resultFormat = 'time_series'; this.target.format = 'time_series';
this.target.alias = ""; this.target.alias = "";
this.resultFormats = [ this.formats = [
{text: 'Time series', value: 'time_series'}, {text: 'Time series', value: 'time_series'},
{text: 'Table', value: 'table'}, {text: 'Table', value: 'table'},
]; ];
this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
}
onDataReceived(dataList) {
this.lastQueryMeta = null;
this.lastQueryError = null;
let anySeriesFromQuery = _.find(dataList, {refId: this.target.refId});
if (anySeriesFromQuery) {
this.lastQueryMeta = anySeriesFromQuery.meta;
}
}
onDataError(err) {
if (err.data && err.data.results) {
let queryRes = err.data.results[this.target.refId];
if (queryRes) {
this.lastQueryMeta = queryRes.meta;
this.lastQueryError = queryRes.error;
}
}
} }
} }

View File

@ -9,7 +9,7 @@
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword">Format as</label> <label class="gf-form-label query-keyword">Format as</label>
<div class="gf-form-select-wrapper"> <div class="gf-form-select-wrapper">
<select class="gf-form-input gf-size-auto" ng-model="ctrl.target.resultFormat" ng-options="f.value as f.text for f in ctrl.resultFormats" ng-change="ctrl.refresh()"></select> <select class="gf-form-input gf-size-auto" ng-model="ctrl.target.format" ng-options="f.value as f.text for f in ctrl.formats" ng-change="ctrl.refresh()"></select>
</div> </div>
</div> </div>
<div class="gf-form max-width-30"> <div class="gf-form max-width-30">
@ -22,4 +22,20 @@
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-show="ctrl.lastQueryMeta">
<div class="gf-form">
<label class="gf-form-label query-keyword" ng-click="ctrl.showLastQuerySQL = !ctrl.showLastQuerySQL">
Generated SQL
<i class="fa fa-caret-down" ng-show="ctrl.showLastQuerySQL"></i>
<i class="fa fa-caret-right" ng-hide="ctrl.showLastQuerySQL"></i>
</label>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<pre class="small" ng-show="ctrl.showLastQuerySQL">{{ctrl.lastQueryMeta.sql}}</pre>
<pre class="small alert alert-error" ng-show="ctrl.lastQueryError">{{ctrl.lastQueryError}}</pre>
</query-editor-row> </query-editor-row>