mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #9186 from mtanda/prometehus_instant_query2
(prometheus) instant query support
This commit is contained in:
@@ -99,6 +99,7 @@ export class PrometheusDatasource {
|
|||||||
var query: any = {};
|
var query: any = {};
|
||||||
query.expr = this.templateSrv.replace(target.expr, options.scopedVars, self.interpolateQueryExpr);
|
query.expr = this.templateSrv.replace(target.expr, options.scopedVars, self.interpolateQueryExpr);
|
||||||
query.requestId = options.panelId + target.refId;
|
query.requestId = options.panelId + target.refId;
|
||||||
|
query.instant = target.instant;
|
||||||
|
|
||||||
var interval = this.templateSrv.replace(target.interval, options.scopedVars) || options.interval;
|
var interval = this.templateSrv.replace(target.interval, options.scopedVars) || options.interval;
|
||||||
var intervalFactor = target.intervalFactor || 1;
|
var intervalFactor = target.intervalFactor || 1;
|
||||||
@@ -114,7 +115,11 @@ export class PrometheusDatasource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var allQueryPromise = _.map(queries, query => {
|
var allQueryPromise = _.map(queries, query => {
|
||||||
return this.performTimeSeriesQuery(query, start, end);
|
if (!query.instant) {
|
||||||
|
return this.performTimeSeriesQuery(query, start, end);
|
||||||
|
} else {
|
||||||
|
return this.performInstantQuery(query, end);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.$q.all(allQueryPromise).then(responseList => {
|
return this.$q.all(allQueryPromise).then(responseList => {
|
||||||
@@ -129,7 +134,11 @@ export class PrometheusDatasource {
|
|||||||
result.push(self.transformMetricDataToTable(response.data.data.result));
|
result.push(self.transformMetricDataToTable(response.data.data.result));
|
||||||
} else {
|
} else {
|
||||||
for (let metricData of response.data.data.result) {
|
for (let metricData of response.data.data.result) {
|
||||||
result.push(self.transformMetricData(metricData, activeTargets[index], start, end));
|
if (response.data.data.resultType === 'matrix') {
|
||||||
|
result.push(self.transformMetricData(metricData, activeTargets[index], start, end));
|
||||||
|
} else if (response.data.data.resultType === 'vector') {
|
||||||
|
result.push(self.transformInstantMetricData(metricData, activeTargets[index]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -156,6 +165,11 @@ export class PrometheusDatasource {
|
|||||||
return this._request('GET', url, query.requestId);
|
return this._request('GET', url, query.requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
performInstantQuery(query, time) {
|
||||||
|
var url = '/api/v1/query?query=' + encodeURIComponent(query.expr) + '&time=' + time;
|
||||||
|
return this._request('GET', url, query.requestId);
|
||||||
|
}
|
||||||
|
|
||||||
performSuggestQuery(query, cache = false) {
|
performSuggestQuery(query, cache = false) {
|
||||||
var url = '/api/v1/label/__name__/values';
|
var url = '/api/v1/label/__name__/values';
|
||||||
|
|
||||||
@@ -317,6 +331,9 @@ export class PrometheusDatasource {
|
|||||||
|
|
||||||
// Populate rows, set value to empty string when label not present.
|
// Populate rows, set value to empty string when label not present.
|
||||||
_.each(md, function(series) {
|
_.each(md, function(series) {
|
||||||
|
if (series.value) {
|
||||||
|
series.values = [series.value];
|
||||||
|
}
|
||||||
if (series.values) {
|
if (series.values) {
|
||||||
for (i = 0; i < series.values.length; i++) {
|
for (i = 0; i < series.values.length; i++) {
|
||||||
var values = series.values[i];
|
var values = series.values[i];
|
||||||
@@ -340,6 +357,13 @@ export class PrometheusDatasource {
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transformInstantMetricData(md, options) {
|
||||||
|
var dps = [], metricLabel = null;
|
||||||
|
metricLabel = this.createMetricLabel(md.metric, options);
|
||||||
|
dps.push([parseFloat(md.value[1]), md.value[0] * 1000]);
|
||||||
|
return { target: metricLabel, datapoints: dps };
|
||||||
|
}
|
||||||
|
|
||||||
createMetricLabel(labelData, options) {
|
createMetricLabel(labelData, options) {
|
||||||
if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) {
|
if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) {
|
||||||
return this.getOriginalMetricName(labelData);
|
return this.getOriginalMetricName(labelData);
|
||||||
|
|||||||
@@ -95,9 +95,7 @@ function (_) {
|
|||||||
|
|
||||||
PrometheusMetricFindQuery.prototype.queryResultQuery = function(query) {
|
PrometheusMetricFindQuery.prototype.queryResultQuery = function(query) {
|
||||||
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||||
var url = '/api/v1/query?query=' + encodeURIComponent(query) + '&time=' + end;
|
return this.datasource.performInstantQuery({ expr: query }, end)
|
||||||
|
|
||||||
return this.datasource._request('GET', url)
|
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
return _.map(result.data.data.result, function(metricData) {
|
return _.map(result.data.data.result, function(metricData) {
|
||||||
var text = metricData.metric.__name__ || '';
|
var text = metricData.metric.__name__ || '';
|
||||||
|
|||||||
@@ -45,6 +45,8 @@
|
|||||||
<div class="gf-form-select-wrapper width-8">
|
<div class="gf-form-select-wrapper width-8">
|
||||||
<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>
|
<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>
|
||||||
|
<gf-form-switch class="gf-form" label="Instant" label-class="width-5" checked="ctrl.target.instant" on-change="ctrl.refresh()">
|
||||||
|
</gf-form-switch>
|
||||||
<label class="gf-form-label">
|
<label class="gf-form-label">
|
||||||
<a href="{{ctrl.linkToPrometheus}}" target="_blank" bs-tooltip="'Link to Graph in Prometheus'">
|
<a href="{{ctrl.linkToPrometheus}}" target="_blank" bs-tooltip="'Link to Graph in Prometheus'">
|
||||||
<i class="fa fa-share-square-o"></i>
|
<i class="fa fa-share-square-o"></i>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class PrometheusQueryCtrl extends QueryCtrl {
|
|||||||
metric: any;
|
metric: any;
|
||||||
resolutions: any;
|
resolutions: any;
|
||||||
formats: any;
|
formats: any;
|
||||||
|
instant: any;
|
||||||
oldTarget: any;
|
oldTarget: any;
|
||||||
suggestMetrics: any;
|
suggestMetrics: any;
|
||||||
getMetricsAutocomplete: any;
|
getMetricsAutocomplete: any;
|
||||||
@@ -36,6 +37,8 @@ class PrometheusQueryCtrl extends QueryCtrl {
|
|||||||
{text: 'Table', value: 'table'},
|
{text: 'Table', value: 'table'},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
this.instant = false;
|
||||||
|
|
||||||
this.updateLink();
|
this.updateLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ describe('PrometheusDatasource', function() {
|
|||||||
'&start=1443438675&end=1443460275&step=60';
|
'&start=1443438675&end=1443460275&step=60';
|
||||||
var query = {
|
var query = {
|
||||||
range: { from: moment(1443438674760), to: moment(1443460274760) },
|
range: { from: moment(1443438674760), to: moment(1443460274760) },
|
||||||
targets: [{ expr: 'test{job="testjob"}' }],
|
targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
|
||||||
interval: '60s'
|
interval: '60s'
|
||||||
};
|
};
|
||||||
var response = {
|
var response = {
|
||||||
@@ -62,7 +62,7 @@ describe('PrometheusDatasource', function() {
|
|||||||
'&start=' + start + '&end=' + end + '&step=' + step;
|
'&start=' + start + '&end=' + end + '&step=' + step;
|
||||||
var query = {
|
var query = {
|
||||||
range: { from: moment(1443438674760), to: moment(1443460274760) },
|
range: { from: moment(1443438674760), to: moment(1443460274760) },
|
||||||
targets: [{ expr: 'test{job="testjob"}' }],
|
targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
|
||||||
interval: '60s'
|
interval: '60s'
|
||||||
};
|
};
|
||||||
var response = {
|
var response = {
|
||||||
@@ -119,7 +119,40 @@ describe('PrometheusDatasource', function() {
|
|||||||
expect(results.data[1].datapoints[3][0]).to.be(null);
|
expect(results.data[1].datapoints[3][0]).to.be(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('When performing annotationQuery', function() {
|
describe('When querying prometheus with one target and instant = true', function () {
|
||||||
|
var results;
|
||||||
|
var urlExpected = 'proxied/api/v1/query?query=' +
|
||||||
|
encodeURIComponent('test{job="testjob"}') +
|
||||||
|
'&time=1443460275';
|
||||||
|
var query = {
|
||||||
|
range: { from: moment(1443438674760), to: moment(1443460274760) },
|
||||||
|
targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }],
|
||||||
|
interval: '60s'
|
||||||
|
};
|
||||||
|
var response = {
|
||||||
|
status: "success",
|
||||||
|
data: {
|
||||||
|
resultType: "vector",
|
||||||
|
result: [{
|
||||||
|
metric: { "__name__": "test", job: "testjob" },
|
||||||
|
value: [1443454528, "3846"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
beforeEach(function () {
|
||||||
|
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
|
||||||
|
ctx.ds.query(query).then(function (data) { results = data; });
|
||||||
|
ctx.$httpBackend.flush();
|
||||||
|
});
|
||||||
|
it('should generate the correct query', function () {
|
||||||
|
ctx.$httpBackend.verifyNoOutstandingExpectation();
|
||||||
|
});
|
||||||
|
it('should return series list', function () {
|
||||||
|
expect(results.data.length).to.be(1);
|
||||||
|
expect(results.data[0].target).to.be('test{job="testjob"}');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('When performing annotationQuery', function () {
|
||||||
var results;
|
var results;
|
||||||
var urlExpected = 'proxied/api/v1/query_range?query=' +
|
var urlExpected = 'proxied/api/v1/query_range?query=' +
|
||||||
encodeURIComponent('ALERTS{alertstate="firing"}') +
|
encodeURIComponent('ALERTS{alertstate="firing"}') +
|
||||||
@@ -195,4 +228,45 @@ describe('PrometheusDatasource', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('When resultFormat is table and instant = true', function() {
|
||||||
|
var results;
|
||||||
|
var urlExpected = 'proxied/api/v1/query?query=' +
|
||||||
|
encodeURIComponent('test{job="testjob"}') +
|
||||||
|
'&time=1443460275';
|
||||||
|
var query = {
|
||||||
|
range: { from: moment(1443438674760), to: moment(1443460274760) },
|
||||||
|
targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }],
|
||||||
|
interval: '60s'
|
||||||
|
};
|
||||||
|
var response = {
|
||||||
|
status: "success",
|
||||||
|
data: {
|
||||||
|
resultType: "vector",
|
||||||
|
result: [{
|
||||||
|
metric: { "__name__": "test", job: "testjob" },
|
||||||
|
value: [1443454528, "3846"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
beforeEach(function () {
|
||||||
|
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
|
||||||
|
ctx.ds.query(query).then(function (data) { results = data; });
|
||||||
|
ctx.$httpBackend.flush();
|
||||||
|
});
|
||||||
|
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' }
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user