From afa539368fe492880a5bda3a9d29d3ece76ffcf6 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Tue, 5 Jan 2016 01:22:37 +0900 Subject: [PATCH 1/3] fill null in Prometheus --- .../plugins/datasource/prometheus/datasource.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/datasource.js b/public/app/plugins/datasource/prometheus/datasource.js index 9560fe8aa5f..1e2b840daec 100644 --- a/public/app/plugins/datasource/prometheus/datasource.js +++ b/public/app/plugins/datasource/prometheus/datasource.js @@ -91,7 +91,7 @@ function (angular, _, moment, dateMath) { delete self.lastErrors.query; _.each(response.data.data.result, function(metricData) { - result.push(transformMetricData(metricData, options.targets[index])); + result.push(transformMetricData(metricData, options.targets[index], start, end)); }); }); @@ -207,14 +207,14 @@ function (angular, _, moment, dateMath) { return Math.ceil(sec * intervalFactor); }; - function transformMetricData(md, options) { + function transformMetricData(md, options, start, end) { var dps = [], metricLabel = null; metricLabel = createMetricLabel(md.metric, options); var stepMs = parseInt(options.step) * 1000; - var lastTimestamp = null; + var baseTimestamp = start * 1000; _.each(md.values, function(value) { var dp_value = parseFloat(value[1]); if (_.isNaN(dp_value)) { @@ -222,13 +222,18 @@ function (angular, _, moment, dateMath) { } var timestamp = value[0] * 1000; - if (lastTimestamp && (timestamp - lastTimestamp) > stepMs) { - dps.push([null, lastTimestamp + stepMs]); + for (var t = baseTimestamp; t < timestamp; t += stepMs) { + dps.push([null, t]); } - lastTimestamp = timestamp; + baseTimestamp = timestamp + stepMs; dps.push([dp_value, timestamp]); }); + var endTimestamp = end * 1000; + for (var t = baseTimestamp; t < endTimestamp; t += stepMs) { + dps.push([null, t]); + } + return { target: metricLabel, datapoints: dps }; } From ff8b25a50a405fd4e4dc95bf0a644274adf4bc80 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Tue, 12 Jan 2016 02:58:51 +0900 Subject: [PATCH 2/3] fix, should fill null at end timestamp --- public/app/plugins/datasource/prometheus/datasource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/prometheus/datasource.js b/public/app/plugins/datasource/prometheus/datasource.js index 1e2b840daec..1ab8486ef40 100644 --- a/public/app/plugins/datasource/prometheus/datasource.js +++ b/public/app/plugins/datasource/prometheus/datasource.js @@ -230,7 +230,7 @@ function (angular, _, moment, dateMath) { }); var endTimestamp = end * 1000; - for (var t = baseTimestamp; t < endTimestamp; t += stepMs) { + for (var t = baseTimestamp; t <= endTimestamp; t += stepMs) { dps.push([null, t]); } From c317149a081b75eb26fa61985bfb2d2327137987 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Tue, 12 Jan 2016 02:37:21 +0900 Subject: [PATCH 3/3] add test for prometheus fill null --- .../prometheus/specs/datasource_specs.ts | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts b/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts index 92620678eaf..d331410ac60 100644 --- a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts @@ -49,6 +49,73 @@ describe('PrometheusDatasource', function() { expect(results.data[0].target).to.be('test{job="testjob"}'); }); }); + describe('When querying prometheus with one target which return multiple series', function() { + var results; + var start = 1443438675; + var end = 1443460275; + var step = 60; + var urlExpected = 'proxied/api/v1/query_range?query=' + + encodeURIComponent('test{job="testjob"}') + + '&start=' + start + '&end=' + end + '&step=' + step; + var query = { + range: { from: moment(1443438674760), to: moment(1443460274760) }, + targets: [{ expr: 'test{job="testjob"}' }], + interval: '60s' + }; + var response = { + status: "success", + data: { + resultType: "matrix", + result: [ + { + metric: {"__name__": "test", job: "testjob", series: 'series 1'}, + values: [ + [start + step * 1, "3846"], + [start + step * 3, "3847"], + [end - step * 1, "3848"], + ] + }, + { + metric: {"__name__": "test", job: "testjob", series: 'series 2'}, + values: [ + [start + step * 2, "4846"] + ] + }, + ] + } + }; + beforeEach(function() { + ctx.$httpBackend.expect('GET', urlExpected).respond(response); + ctx.ds.query(query).then(function(data) { results = data; }); + ctx.$httpBackend.flush(); + }); + it('should be same length', function() { + expect(results.data.length).to.be(2); + expect(results.data[0].datapoints.length).to.be((end - start) / step + 1); + expect(results.data[1].datapoints.length).to.be((end - start) / step + 1); + }); + it('should fill null until first datapoint in response', function() { + expect(results.data[0].datapoints[0][1]).to.be(start * 1000); + expect(results.data[0].datapoints[0][0]).to.be(null); + expect(results.data[0].datapoints[1][1]).to.be((start + step * 1) * 1000); + expect(results.data[0].datapoints[1][0]).to.be(3846); + }); + it('should fill null after last datapoint in response', function() { + var length = (end - start) / step + 1; + expect(results.data[0].datapoints[length-2][1]).to.be((end - step * 1) * 1000); + expect(results.data[0].datapoints[length-2][0]).to.be(3848); + expect(results.data[0].datapoints[length-1][1]).to.be(end * 1000); + expect(results.data[0].datapoints[length-1][0]).to.be(null); + }); + it('should fill null at gap between series', function() { + expect(results.data[0].datapoints[2][1]).to.be((start + step * 2) * 1000); + expect(results.data[0].datapoints[2][0]).to.be(null); + expect(results.data[1].datapoints[1][1]).to.be((start + step * 1) * 1000); + expect(results.data[1].datapoints[1][0]).to.be(null); + expect(results.data[1].datapoints[3][1]).to.be((start + step * 3) * 1000); + expect(results.data[1].datapoints[3][0]).to.be(null); + }); + }); describe('When performing metricFindQuery', function() { var results; var response;