diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 4b4bfb4cdde..3544a702f29 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -100,6 +100,7 @@ export class PrometheusDatasource { var query: any = {}; query.expr = this.templateSrv.replace(target.expr, options.scopedVars, self.interpolateQueryExpr); query.requestId = options.panelId + target.refId; + query.format = target.format; var interval = this.templateSrv.replace(target.interval, options.scopedVars) || options.interval; var intervalFactor = target.intervalFactor || 1; @@ -115,7 +116,11 @@ export class PrometheusDatasource { } var allQueryPromise = _.map(queries, query => { - return this.performTimeSeriesQuery(query, start, end); + if (query.format === 'time_series') { + return this.performTimeSeriesQuery(query, start, end); + } else { + return this.performInstantQuery(query, end); + } }); return this.$q.all(allQueryPromise).then(responseList => { @@ -131,7 +136,11 @@ export class PrometheusDatasource { 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)); + 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])); + } } } }); @@ -158,6 +167,11 @@ export class PrometheusDatasource { 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) { var url = '/api/v1/label/__name__/values'; @@ -342,6 +356,13 @@ export class PrometheusDatasource { 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) { if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) { return this.getOriginalMetricName(labelData); diff --git a/public/app/plugins/datasource/prometheus/query_ctrl.ts b/public/app/plugins/datasource/prometheus/query_ctrl.ts index 17a564d0b46..9a3a9603f61 100644 --- a/public/app/plugins/datasource/prometheus/query_ctrl.ts +++ b/public/app/plugins/datasource/prometheus/query_ctrl.ts @@ -36,6 +36,7 @@ class PrometheusQueryCtrl extends QueryCtrl { this.formats = [ {text: 'Time series', value: 'time_series'}, {text: 'Table', value: 'table'}, + {text: 'Instant', value: 'instant'}, ]; this.updateLink(); diff --git a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts b/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts index 9588090c7bb..95ccbbb6325 100644 --- a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts @@ -26,7 +26,7 @@ describe('PrometheusDatasource', function() { '&start=1443438675&end=1443460275&step=60'; var query = { range: { from: moment(1443438674760), to: moment(1443460274760) }, - targets: [{ expr: 'test{job="testjob"}' }], + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], interval: '60s' }; var response = { @@ -62,7 +62,7 @@ describe('PrometheusDatasource', function() { '&start=' + start + '&end=' + end + '&step=' + step; var query = { range: { from: moment(1443438674760), to: moment(1443460274760) }, - targets: [{ expr: 'test{job="testjob"}' }], + targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }], interval: '60s' }; var response = { @@ -119,7 +119,40 @@ describe('PrometheusDatasource', function() { expect(results.data[1].datapoints[3][0]).to.be(null); }); }); - describe('When performing annotationQuery', function() { + describe('When querying prometheus with one target and format = instant', 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: 'instant' }], + 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 urlExpected = 'proxied/api/v1/query_range?query=' + encodeURIComponent('ALERTS{alertstate="firing"}') +