From aae25c530873c0db51d987d1a1bfe84aeda0b3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Bedi?= Date: Thu, 13 Aug 2020 18:58:40 +0200 Subject: [PATCH] Prometheus: add $__rate_interval variable (#26937) * Add rate interval variable to prometheus data source * Add tests + auto complete * Fix prometheus tests * Add doc * Modify test title * Modify kbn method name after merge --- .../features/datasources/prometheus.md | 3 +++ .../datasource/prometheus/datasource.test.ts | 19 +++++++++++++++++++ .../datasource/prometheus/datasource.ts | 17 ++++++++++++++++- .../prometheus/language_provider.test.ts | 1 + .../plugins/datasource/prometheus/promql.ts | 1 + 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/docs/sources/features/datasources/prometheus.md b/docs/sources/features/datasources/prometheus.md index c58febd6ab5..65e5a6254b9 100644 --- a/docs/sources/features/datasources/prometheus.md +++ b/docs/sources/features/datasources/prometheus.md @@ -110,6 +110,9 @@ Populate a variable with the instances having a certain state over the time rang Query: query_result(max_over_time([${__range_s}s]) != ) Regex: ``` +### Using `$__rate_interval` variable + +The `$__rate_interval` variable is meant to be used in the rate function. It is defined as max( `$__interval` + _Scrape interval_, 4 * _Scrape interval_), where _Scrape interval_ is the Min step setting (AKA query_interval, a setting per PromQL query), if any is set, and otherwise the _Scrape interval_ as set in the Prometheus data source (but ignoring any Min interval setting in the panel, because the latter is modified by the resolution setting). ### Using variables in queries diff --git a/public/app/plugins/datasource/prometheus/datasource.test.ts b/public/app/plugins/datasource/prometheus/datasource.test.ts index 86b540717ef..1b3610663b0 100644 --- a/public/app/plugins/datasource/prometheus/datasource.test.ts +++ b/public/app/plugins/datasource/prometheus/datasource.test.ts @@ -1601,9 +1601,28 @@ describe('PrometheusDatasource', () => { text: expectedRangeSecond * 1000, value: expectedRangeSecond * 1000, }, + __rate_interval: { + text: '75s', + value: '75s', + }, }); }); }); + + describe('The __rate_interval variable', () => { + it('should be 4 times the scrape interval if interval + scrape interval is lower', () => { + const { __rate_interval } = ds.getRateIntervalScopedVariable(23, 23); + expect(__rate_interval.value).toBe('60s'); + }); + it('should be interval + scrape interval if 4 times the scrape interval is lower', () => { + const { __rate_interval } = ds.getRateIntervalScopedVariable(56, 56); + expect(__rate_interval.value).toBe('71s'); + }); + it('should fall back to 60s if interval is 0', () => { + const { __rate_interval } = ds.getRateIntervalScopedVariable(0, 0); + expect(__rate_interval.value).toBe('60s'); + }); + }); }); describe('PrometheusDatasource for POST', () => { diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index b21a60095db..9e2ce91adf0 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -335,13 +335,18 @@ export class PrometheusDatasource extends DataSourceApi const intervalFactor = target.intervalFactor || 1; // Adjust the interval to take into account any specified minimum and interval factor plus Prometheus limits const adjustedInterval = this.adjustInterval(interval, minInterval, range, intervalFactor); - let scopedVars = { ...options.scopedVars, ...this.getRangeScopedVars(options.range) }; + let scopedVars = { + ...options.scopedVars, + ...this.getRangeScopedVars(options.range), + ...this.getRateIntervalScopedVariable(interval, minInterval), + }; // If the interval was adjusted, make a shallow copy of scopedVars with updated interval vars if (interval !== adjustedInterval) { interval = adjustedInterval; scopedVars = Object.assign({}, options.scopedVars, { __interval: { text: interval + 's', value: interval + 's' }, __interval_ms: { text: interval * 1000, value: interval * 1000 }, + ...this.getRateIntervalScopedVariable(interval, minInterval), ...this.getRangeScopedVars(options.range), }); } @@ -380,6 +385,16 @@ export class PrometheusDatasource extends DataSourceApi return query; } + getRateIntervalScopedVariable(interval: number, minInterval: number) { + let intervalInSeconds = minInterval === interval ? kbn.intervalToSeconds(this.interval) : minInterval; + // if intervalInSeconds === 0 then we should fall back to the default 15 seconds + if (intervalInSeconds === 0) { + intervalInSeconds = 15; + } + const rateInterval = Math.max(interval + intervalInSeconds, 4 * intervalInSeconds); + return { __rate_interval: { text: rateInterval + 's', value: rateInterval + 's' } }; + } + adjustInterval(interval: number, minInterval: number, range: number, intervalFactor: number) { // Prometheus will drop queries that might return more than 11000 data points. // Calculate a safe interval as an additional minimum to take into account. diff --git a/public/app/plugins/datasource/prometheus/language_provider.test.ts b/public/app/plugins/datasource/prometheus/language_provider.test.ts index 970cbec4dbe..c1a101ce2de 100644 --- a/public/app/plugins/datasource/prometheus/language_provider.test.ts +++ b/public/app/plugins/datasource/prometheus/language_provider.test.ts @@ -124,6 +124,7 @@ describe('Language completion provider', () => { { items: [ { label: '$__interval', sortText: '$__interval' }, // TODO: figure out why this row and sortText is needed + { label: '$__rate_interval', sortText: '$__rate_interval' }, { label: '1m', sortText: '00:01:00' }, { label: '5m', sortText: '00:05:00' }, { label: '10m', sortText: '00:10:00' }, diff --git a/public/app/plugins/datasource/prometheus/promql.ts b/public/app/plugins/datasource/prometheus/promql.ts index d4b68200ba6..d59cdf92262 100644 --- a/public/app/plugins/datasource/prometheus/promql.ts +++ b/public/app/plugins/datasource/prometheus/promql.ts @@ -2,6 +2,7 @@ import { CompletionItem } from '@grafana/ui'; export const RATE_RANGES: CompletionItem[] = [ { label: '$__interval', sortText: '$__interval' }, + { label: '$__rate_interval', sortText: '$__rate_interval' }, { label: '1m', sortText: '00:01:00' }, { label: '5m', sortText: '00:05:00' }, { label: '10m', sortText: '00:10:00' },