Skip to content

Commit f70252f

Browse files
committed
Merge pull request grafana#3661 from mtanda/prometheus_fill_null
(prometheus) fill null for missing data point
2 parents ed989ec + c317149 commit f70252f

File tree

2 files changed

+78
-6
lines changed

2 files changed

+78
-6
lines changed

public/app/plugins/datasource/prometheus/datasource.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ function (angular, _, moment, dateMath) {
9191
delete self.lastErrors.query;
9292

9393
_.each(response.data.data.result, function(metricData) {
94-
result.push(transformMetricData(metricData, options.targets[index]));
94+
result.push(transformMetricData(metricData, options.targets[index], start, end));
9595
});
9696
});
9797

@@ -207,28 +207,33 @@ function (angular, _, moment, dateMath) {
207207
return Math.ceil(sec * intervalFactor);
208208
};
209209

210-
function transformMetricData(md, options) {
210+
function transformMetricData(md, options, start, end) {
211211
var dps = [],
212212
metricLabel = null;
213213

214214
metricLabel = createMetricLabel(md.metric, options);
215215

216216
var stepMs = parseInt(options.step) * 1000;
217-
var lastTimestamp = null;
217+
var baseTimestamp = start * 1000;
218218
_.each(md.values, function(value) {
219219
var dp_value = parseFloat(value[1]);
220220
if (_.isNaN(dp_value)) {
221221
dp_value = null;
222222
}
223223

224224
var timestamp = value[0] * 1000;
225-
if (lastTimestamp && (timestamp - lastTimestamp) > stepMs) {
226-
dps.push([null, lastTimestamp + stepMs]);
225+
for (var t = baseTimestamp; t < timestamp; t += stepMs) {
226+
dps.push([null, t]);
227227
}
228-
lastTimestamp = timestamp;
228+
baseTimestamp = timestamp + stepMs;
229229
dps.push([dp_value, timestamp]);
230230
});
231231

232+
var endTimestamp = end * 1000;
233+
for (var t = baseTimestamp; t <= endTimestamp; t += stepMs) {
234+
dps.push([null, t]);
235+
}
236+
232237
return { target: metricLabel, datapoints: dps };
233238
}
234239

public/app/plugins/datasource/prometheus/specs/datasource_specs.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,73 @@ describe('PrometheusDatasource', function() {
4949
expect(results.data[0].target).to.be('test{job="testjob"}');
5050
});
5151
});
52+
describe('When querying prometheus with one target which return multiple series', function() {
53+
var results;
54+
var start = 1443438675;
55+
var end = 1443460275;
56+
var step = 60;
57+
var urlExpected = 'proxied/api/v1/query_range?query=' +
58+
encodeURIComponent('test{job="testjob"}') +
59+
'&start=' + start + '&end=' + end + '&step=' + step;
60+
var query = {
61+
range: { from: moment(1443438674760), to: moment(1443460274760) },
62+
targets: [{ expr: 'test{job="testjob"}' }],
63+
interval: '60s'
64+
};
65+
var response = {
66+
status: "success",
67+
data: {
68+
resultType: "matrix",
69+
result: [
70+
{
71+
metric: {"__name__": "test", job: "testjob", series: 'series 1'},
72+
values: [
73+
[start + step * 1, "3846"],
74+
[start + step * 3, "3847"],
75+
[end - step * 1, "3848"],
76+
]
77+
},
78+
{
79+
metric: {"__name__": "test", job: "testjob", series: 'series 2'},
80+
values: [
81+
[start + step * 2, "4846"]
82+
]
83+
},
84+
]
85+
}
86+
};
87+
beforeEach(function() {
88+
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
89+
ctx.ds.query(query).then(function(data) { results = data; });
90+
ctx.$httpBackend.flush();
91+
});
92+
it('should be same length', function() {
93+
expect(results.data.length).to.be(2);
94+
expect(results.data[0].datapoints.length).to.be((end - start) / step + 1);
95+
expect(results.data[1].datapoints.length).to.be((end - start) / step + 1);
96+
});
97+
it('should fill null until first datapoint in response', function() {
98+
expect(results.data[0].datapoints[0][1]).to.be(start * 1000);
99+
expect(results.data[0].datapoints[0][0]).to.be(null);
100+
expect(results.data[0].datapoints[1][1]).to.be((start + step * 1) * 1000);
101+
expect(results.data[0].datapoints[1][0]).to.be(3846);
102+
});
103+
it('should fill null after last datapoint in response', function() {
104+
var length = (end - start) / step + 1;
105+
expect(results.data[0].datapoints[length-2][1]).to.be((end - step * 1) * 1000);
106+
expect(results.data[0].datapoints[length-2][0]).to.be(3848);
107+
expect(results.data[0].datapoints[length-1][1]).to.be(end * 1000);
108+
expect(results.data[0].datapoints[length-1][0]).to.be(null);
109+
});
110+
it('should fill null at gap between series', function() {
111+
expect(results.data[0].datapoints[2][1]).to.be((start + step * 2) * 1000);
112+
expect(results.data[0].datapoints[2][0]).to.be(null);
113+
expect(results.data[1].datapoints[1][1]).to.be((start + step * 1) * 1000);
114+
expect(results.data[1].datapoints[1][0]).to.be(null);
115+
expect(results.data[1].datapoints[3][1]).to.be((start + step * 3) * 1000);
116+
expect(results.data[1].datapoints[3][0]).to.be(null);
117+
});
118+
});
52119
describe('When performing metricFindQuery', function() {
53120
var results;
54121
var response;

0 commit comments

Comments
 (0)