Commit 6ff1144a by Torkel Ödegaard

refactoring: prometheus PR #6140

parents 787fea90 d018d2a2
......@@ -7,6 +7,7 @@ import moment from 'moment';
import kbn from 'app/core/utils/kbn';
import * as dateMath from 'app/core/utils/datemath';
import PrometheusMetricFindQuery from './metric_find_query';
import TableModel from 'app/core/table_model';
var durationSplitRegexp = /(\d+)(ms|s|m|h|d|w|M|y)/;
......@@ -20,7 +21,6 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
this.directUrl = instanceSettings.directUrl;
this.basicAuth = instanceSettings.basicAuth;
this.withCredentials = instanceSettings.withCredentials;
this.lastErrors = {};
this._request = function(method, url, requestId) {
var options: any = {
......@@ -74,7 +74,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
options = _.clone(options);
_.each(options.targets, target => {
for (let target of options.targets) {
if (!target.expr || target.hide) {
return;
}
......@@ -91,31 +91,33 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
var range = Math.ceil(end - start);
target.step = query.step = this.adjustStep(query.step, this.intervalSeconds(options.interval), range);
queries.push(query);
});
}
// No valid targets, return the empty result to save a round trip.
if (_.isEmpty(queries)) {
var d = $q.defer();
d.resolve({ data: [] });
return d.promise;
return $q.when({ data: [] });
}
var allQueryPromise = _.map(queries, query => {
return this.performTimeSeriesQuery(query, start, end);
});
return $q.all(allQueryPromise).then(function(allResponse) {
return $q.all(allQueryPromise).then(responseList => {
var result = [];
var index = 0;
_.each(allResponse, function(response, index) {
_.each(responseList, (response, index) => {
if (response.status === 'error') {
self.lastErrors.query = response.error;
throw response.error;
}
delete self.lastErrors.query;
_.each(response.data.data.result, function(metricData) {
result.push(self.transformMetricData(metricData, activeTargets[index], start, end));
});
if (activeTargets[index].format === "table") {
result.push(self.transformMetricDataToTable(response.data.data.result));
} else {
for (let metricData of response.data.data.result) {
result.push(self.transformMetricData(metricData, activeTargets[index], start, end));
}
}
});
return { data: result };
......@@ -273,6 +275,44 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
return { target: metricLabel, datapoints: dps };
};
this.transformMetricDataToTable = function(series) {
var table = new TableModel();
var self = this;
var i, j;
if (series.length === 0) {
return table;
}
_.each(series, function(series, seriesIndex) {
if (seriesIndex === 0) {
table.columns.push({text: 'Time', type: 'time'});
_.each(_.keys(series.metric), function(key) {
table.columns.push({text: key});
});
table.columns.push({text: 'Value'});
}
if (series.values) {
for (i = 0; i < series.values.length; i++) {
var values = series.values[i];
var reordered = [values[0] * 1000];
if (series.metric) {
for (var key in series.metric) {
if (series.metric.hasOwnProperty(key)) {
reordered.push(series.metric[key]);
}
}
}
reordered.push(parseFloat(values[1]));
table.rows.push(reordered);
}
}
});
return table;
};
this.createMetricLabel = function(labelData, options) {
if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) {
return this.getOriginalMetricName(labelData);
......
......@@ -42,6 +42,10 @@
</div>
<div class="gf-form">
<label class="gf-form-label">Format as</label>
<div class="gf-form-select-wrapper">
<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>
<label class="gf-form-label">
<a href="{{ctrl.linkToPrometheus}}" target="_blank" bs-tooltip="'Link to Graph in Prometheus'">
<i class="fa fa-share-square-o"></i>
......
......@@ -12,6 +12,7 @@ class PrometheusQueryCtrl extends QueryCtrl {
metric: any;
resolutions: any;
formats: any;
oldTarget: any;
suggestMetrics: any;
linkToPrometheus: any;
......@@ -23,15 +24,20 @@ class PrometheusQueryCtrl extends QueryCtrl {
var target = this.target;
target.expr = target.expr || '';
target.intervalFactor = target.intervalFactor || 2;
target.format = target.format || this.getDefaultFormat();
this.metric = '';
this.resolutions = _.map([1,2,3,4,5,10], function(f) {
return {factor: f, label: '1/' + f};
});
this.formats = [
{text: 'Time series', value: 'time_series'},
{text: 'Table', value: 'table'},
];
$scope.$on('typeahead-updated', () => {
this.$scope.$apply(() => {
this.target.expr += this.target.metric;
this.metric = '';
this.refreshMetricData();
......@@ -48,6 +54,13 @@ class PrometheusQueryCtrl extends QueryCtrl {
this.updateLink();
}
getDefaultFormat() {
if (this.panelCtrl.panel.type === 'table') {
return 'table';
}
return 'time_series';
}
refreshMetricData() {
if (!_.isEqual(this.oldTarget, this.target)) {
this.oldTarget = angular.copy(this.target);
......
......@@ -160,4 +160,28 @@ describe('PrometheusDatasource', function() {
expect(results[0].time).to.be(1443454528 * 1000);
});
});
describe('When resultFormat is table', function() {
var response = {
status: "success",
data: {
resultType: "matrix",
result: [{
metric: {"__name__": "test", job: "testjob"},
values: [[1443454528, "3846"]]
}]
}
};
it('should return table model', function() {
var table = ctx.ds.transformMetricDataToTable(response.data.result);
expect(table.type).to.be('table');
expect(table.rows).to.eql([ [ 1443454528000, 'test', 'testjob', 3846 ] ]);
expect(table.columns).to.eql(
[ { text: 'Time', type: 'time' },
{ text: '__name__' },
{ text: 'job' },
{ text: 'Value' }
]
);
});
});
});
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