Commit 750ea9bb by David Kaltschmidt

Changed Prometheus interval-alignment to cover whole panel range

* the existing query date alignment shifts the range forward to match
a multiple epoch of the interval, but keeps the range length the same,
the result is that the start date is shifted forward as well, leaving a
gap in the graph (or a zero-line when null-as-zero was set, issue #12024)
* this pr extends the aligned range to cover the original start date as
well
parent 21ade3f6
......@@ -7,6 +7,15 @@ import PrometheusMetricFindQuery from './metric_find_query';
import { ResultTransformer } from './result_transformer';
import { BackendSrv } from 'app/core/services/backend_srv';
export function alignRange(start, end, step) {
const alignedEnd = Math.ceil(end / step) * step;
const alignedStart = Math.floor(start / step) * step;
return {
end: alignedEnd,
start: alignedStart,
};
}
export function prometheusRegularEscape(value) {
return value.replace(/'/g, "\\\\'");
}
......@@ -109,15 +118,6 @@ export class PrometheusDatasource {
return this.templateSrv.variableExists(target.expr);
}
clampRange(start, end, step) {
const clampedEnd = Math.ceil(end / step) * step;
const clampedRange = Math.floor((end - start) / step) * step;
return {
end: clampedEnd,
start: clampedEnd - clampedRange,
};
}
query(options) {
var start = this.getPrometheusTime(options.range.from, false);
var end = this.getPrometheusTime(options.range.to, true);
......@@ -205,7 +205,7 @@ export class PrometheusDatasource {
query.requestId = options.panelId + target.refId;
// Align query interval with step
const adjusted = this.clampRange(start, end, query.step);
const adjusted = alignRange(start, end, query.step);
query.start = adjusted.start;
query.end = adjusted.end;
......
import _ from 'lodash';
import moment from 'moment';
import q from 'q';
import { PrometheusDatasource, prometheusSpecialRegexEscape, prometheusRegularEscape } from '../datasource';
import { alignRange, PrometheusDatasource, prometheusSpecialRegexEscape, prometheusRegularEscape } from '../datasource';
describe('PrometheusDatasource', () => {
let ctx: any = {};
......@@ -142,6 +142,29 @@ describe('PrometheusDatasource', () => {
});
});
describe('alignRange', function() {
it('does not modify already aligned intervals with perfect step', function() {
const range = alignRange(0, 3, 3);
expect(range.start).toEqual(0);
expect(range.end).toEqual(3);
});
it('does modify end-aligned intervals to reflect number of steps possible', function() {
const range = alignRange(1, 6, 3);
expect(range.start).toEqual(0);
expect(range.end).toEqual(6);
});
it('does align intervals that are a multiple of steps', function() {
const range = alignRange(1, 4, 3);
expect(range.start).toEqual(0);
expect(range.end).toEqual(6);
});
it('does align intervals that are not a multiple of steps', function() {
const range = alignRange(1, 5, 3);
expect(range.start).toEqual(0);
expect(range.end).toEqual(6);
});
});
describe('Prometheus regular escaping', function() {
it('should not escape simple string', function() {
expect(prometheusRegularEscape('cryptodepression')).toEqual('cryptodepression');
......
......@@ -44,7 +44,7 @@ describe('PrometheusDatasource', function() {
};
// Interval alignment with step
var urlExpected =
'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=120&end=240&step=60';
'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60';
var response = {
status: 'success',
data: {
......@@ -181,7 +181,7 @@ describe('PrometheusDatasource', function() {
var urlExpected =
'proxied/api/v1/query_range?query=' +
encodeURIComponent('ALERTS{alertstate="firing"}') +
'&start=120&end=180&step=60';
'&start=60&end=180&step=60';
var options = {
annotation: {
expr: 'ALERTS{alertstate="firing"}',
......@@ -348,7 +348,7 @@ describe('PrometheusDatasource', function() {
interval: '5s',
};
// times get rounded up to interval
var urlExpected = 'proxied/api/v1/query_range?query=test&start=100&end=450&step=50';
var urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=450&step=50';
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
ctx.ds.query(query);
ctx.$httpBackend.verifyNoOutstandingExpectation();
......@@ -384,8 +384,8 @@ describe('PrometheusDatasource', function() {
],
interval: '10s',
};
// times get rounded up to interval
var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=200&end=500&step=100';
// times get aligned to interval
var urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=500&step=100';
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
ctx.ds.query(query);
ctx.$httpBackend.verifyNoOutstandingExpectation();
......@@ -511,7 +511,7 @@ describe('PrometheusDatasource', function() {
},
};
var urlExpected =
'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[100s])') + '&start=200&end=500&step=100';
'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[100s])') + '&start=0&end=500&step=100';
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
ctx.ds.query(query);
ctx.$httpBackend.verifyNoOutstandingExpectation();
......@@ -539,7 +539,7 @@ describe('PrometheusDatasource', function() {
},
};
var urlExpected =
'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[50s])') + '&start=100&end=450&step=50';
'proxied/api/v1/query_range?query=' + encodeURIComponent('rate(test[50s])') + '&start=50&end=450&step=50';
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
ctx.ds.query(query);
ctx.$httpBackend.verifyNoOutstandingExpectation();
......@@ -613,29 +613,6 @@ describe('PrometheusDatasource', function() {
expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
});
});
describe('Step alignment of intervals', function() {
it('does not modify already aligned intervals with perfect step', function() {
const range = ctx.ds.clampRange(0, 3, 3);
expect(range.start).to.be(0);
expect(range.end).to.be(3);
});
it('does modify end-aligned intervals to reflect number of steps possible', function() {
const range = ctx.ds.clampRange(1, 6, 3);
expect(range.start).to.be(3);
expect(range.end).to.be(6);
});
it('does align intervals that are a multiple of steps', function() {
const range = ctx.ds.clampRange(1, 4, 3);
expect(range.start).to.be(3);
expect(range.end).to.be(6);
});
it('does align intervals that are not a multiple of steps', function() {
const range = ctx.ds.clampRange(1, 5, 3);
expect(range.start).to.be(3);
expect(range.end).to.be(6);
});
});
});
describe('PrometheusDatasource for POST', function() {
......@@ -667,7 +644,7 @@ describe('PrometheusDatasource for POST', function() {
var urlExpected = 'proxied/api/v1/query_range';
var dataExpected = $.param({
query: 'test{job="testjob"}',
start: 2 * 60,
start: 1 * 60,
end: 3 * 60,
step: 60,
});
......
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