From 1827aa942acce0860a52f6a27fc1647e5a11bee6 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 9 Oct 2019 15:15:51 +0300 Subject: [PATCH 1/5] Add $__range_series variable for calculating function over the whole series, #531 --- src/datasource-zabbix/constants.js | 2 ++ src/datasource-zabbix/dataProcessor.js | 3 +-- src/datasource-zabbix/datasource.js | 3 +++ src/datasource-zabbix/timeseries.js | 21 ++++++++++++++++++++- src/datasource-zabbix/utils.js | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/datasource-zabbix/constants.js b/src/datasource-zabbix/constants.js index af3c8d1..79d2edc 100644 --- a/src/datasource-zabbix/constants.js +++ b/src/datasource-zabbix/constants.js @@ -37,3 +37,5 @@ export const TRIGGER_SEVERITY = [ /** Minimum interval for SLA over time (1 hour) */ export const MIN_SLA_INTERVAL = 3600; + +export const RANGE_VARIABLE_VALUE = 'range_series'; diff --git a/src/datasource-zabbix/dataProcessor.js b/src/datasource-zabbix/dataProcessor.js index 4ff8c9e..e69ceda 100644 --- a/src/datasource-zabbix/dataProcessor.js +++ b/src/datasource-zabbix/dataProcessor.js @@ -1,9 +1,8 @@ import _ from 'lodash'; import * as utils from './utils'; -import ts from './timeseries'; +import ts, { groupBy_perf as groupBy } from './timeseries'; let downsampleSeries = ts.downsample; -let groupBy = ts.groupBy_perf; let groupBy_exported = (interval, groupFunc, datapoints) => groupBy(datapoints, interval, groupFunc); let sumSeries = ts.sumSeries; let delta = ts.delta; diff --git a/src/datasource-zabbix/datasource.js b/src/datasource-zabbix/datasource.js index 09faf6d..94c29c8 100644 --- a/src/datasource-zabbix/datasource.js +++ b/src/datasource-zabbix/datasource.js @@ -111,6 +111,9 @@ export class ZabbixDatasource { let timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000); let timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000); + // Add range variables + options.scopedVars = Object.assign({}, options.scopedVars, utils.getRangeScopedVars(options.range)); + // Prevent changes of original object let target = _.cloneDeep(t); diff --git a/src/datasource-zabbix/timeseries.js b/src/datasource-zabbix/timeseries.js index de20b4a..34853e8 100644 --- a/src/datasource-zabbix/timeseries.js +++ b/src/datasource-zabbix/timeseries.js @@ -11,6 +11,7 @@ import _ from 'lodash'; import * as utils from './utils'; +import * as c from './constants'; const POINT_VALUE = 0; const POINT_TIMESTAMP = 1; @@ -94,11 +95,15 @@ function groupBy(datapoints, interval, groupByCallback) { })); } -function groupBy_perf(datapoints, interval, groupByCallback) { +export function groupBy_perf(datapoints, interval, groupByCallback) { if (datapoints.length === 0) { return []; } + if (interval === c.RANGE_VARIABLE_VALUE) { + return groupByRange(datapoints, groupByCallback); + } + let ms_interval = utils.parseInterval(interval); let grouped_series = []; let frame_values = []; @@ -132,6 +137,19 @@ function groupBy_perf(datapoints, interval, groupByCallback) { return grouped_series; } +export function groupByRange(datapoints, groupByCallback) { + const frame_values = []; + const frame_start = datapoints[0][POINT_TIMESTAMP]; + const frame_end = datapoints[datapoints.length - 1][POINT_TIMESTAMP]; + let point; + for (let i=0; i < datapoints.length; i++) { + point = datapoints[i]; + frame_values.push(point[POINT_VALUE]); + } + const frame_value = groupByCallback(frame_values); + return [ [frame_value, frame_start], [frame_value, frame_end] ]; +} + /** * Summarize set of time series into one. * @param {datapoints[]} timeseries array of time series @@ -495,6 +513,7 @@ const exportedFunctions = { downsample, groupBy, groupBy_perf, + groupByRange, sumSeries, scale, offset, diff --git a/src/datasource-zabbix/utils.js b/src/datasource-zabbix/utils.js index 517569f..454ebaa 100644 --- a/src/datasource-zabbix/utils.js +++ b/src/datasource-zabbix/utils.js @@ -1,5 +1,7 @@ import _ from 'lodash'; import moment from 'moment'; +import kbn from 'grafana/app/core/utils/kbn'; +import * as c from './constants'; /** * Expand Zabbix item name @@ -141,6 +143,18 @@ export function isTemplateVariable(str, templateVariables) { } } +export function getRangeScopedVars(range) { + const msRange = range.to.diff(range.from); + const sRange = Math.round(msRange / 1000); + const regularRange = kbn.secondsToHms(msRange / 1000); + return { + __range_ms: { text: msRange, value: msRange }, + __range_s: { text: sRange, value: sRange }, + __range: { text: regularRange, value: regularRange }, + __range_series: {text: c.RANGE_VARIABLE_VALUE, value: c.RANGE_VARIABLE_VALUE}, + }; +} + export function buildRegex(str) { var matches = str.match(regexPattern); var pattern = matches[1]; From 1d13520358c242947a82e563a7039d32ae69198d Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 9 Oct 2019 15:41:02 +0300 Subject: [PATCH 2/5] fix tests --- .../specs/datasource.spec.js | 41 +++++++++---------- src/datasource-zabbix/timeseries.js | 2 +- src/test-setup/jest-setup.js | 1 + 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/datasource-zabbix/specs/datasource.spec.js b/src/datasource-zabbix/specs/datasource.spec.js index 7c95335..dd99f26 100644 --- a/src/datasource-zabbix/specs/datasource.spec.js +++ b/src/datasource-zabbix/specs/datasource.spec.js @@ -2,6 +2,7 @@ import _ from 'lodash'; import mocks from '../../test-setup/mocks'; import { Datasource } from "../module"; import { zabbixTemplateFormat } from "../datasource"; +import { dateMath } from '@grafana/data'; describe('ZabbixDatasource', () => { let ctx = {}; @@ -41,7 +42,10 @@ describe('ZabbixDatasource', () => { item: {filter: ""} } ], - range: {from: 'now-7d', to: 'now'} + range: { + from: dateMath.parse('now-1h'), + to: dateMath.parse('now') + } }; it('should return an empty array when no targets are set', (done) => { @@ -59,7 +63,7 @@ describe('ZabbixDatasource', () => { let ranges = ['now-8d', 'now-169h', 'now-1M', 'now-1y']; _.forEach(ranges, range => { - ctx.options.range.from = range; + ctx.options.range.from = dateMath.parse(range); ctx.ds.queryNumericData = jest.fn(); ctx.ds.query(ctx.options); @@ -76,7 +80,7 @@ describe('ZabbixDatasource', () => { let ranges = ['now-7d', 'now-168h', 'now-1h', 'now-30m', 'now-30s']; _.forEach(ranges, range => { - ctx.options.range.from = range; + ctx.options.range.from = dateMath.parse(range); ctx.ds.queryNumericData = jest.fn(); ctx.ds.query(ctx.options); @@ -108,24 +112,19 @@ describe('ZabbixDatasource', () => { } ])); - ctx.options = { - range: {from: 'now-1h', to: 'now'}, - targets: [ - { - group: {filter: ""}, - host: {filter: "Zabbix server"}, - application: {filter: ""}, - item: {filter: "System information"}, - textFilter: "", - useCaptureGroups: true, - mode: 2, - resultFormat: "table", - options: { - skipEmptyValues: false - } - } - ], - }; + ctx.options.targets = [{ + group: {filter: ""}, + host: {filter: "Zabbix server"}, + application: {filter: ""}, + item: {filter: "System information"}, + textFilter: "", + useCaptureGroups: true, + mode: 2, + resultFormat: "table", + options: { + skipEmptyValues: false + } + }]; }); it('should return data in table format', (done) => { diff --git a/src/datasource-zabbix/timeseries.js b/src/datasource-zabbix/timeseries.js index 34853e8..109fa41 100644 --- a/src/datasource-zabbix/timeseries.js +++ b/src/datasource-zabbix/timeseries.js @@ -147,7 +147,7 @@ export function groupByRange(datapoints, groupByCallback) { frame_values.push(point[POINT_VALUE]); } const frame_value = groupByCallback(frame_values); - return [ [frame_value, frame_start], [frame_value, frame_end] ]; + return [[frame_value, frame_start], [frame_value, frame_end]]; } /** diff --git a/src/test-setup/jest-setup.js b/src/test-setup/jest-setup.js index dedf7a2..6d9ae49 100644 --- a/src/test-setup/jest-setup.js +++ b/src/test-setup/jest-setup.js @@ -45,6 +45,7 @@ jest.mock('grafana/app/core/utils/datemath', () => { jest.mock('grafana/app/core/utils/kbn', () => { return { round_interval: n => n, + secondsToHms: n => n + 'ms' }; }, {virtual: true}); From 51d423e5860ad390b7fe4745ccbaa29fadcb14bd Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 28 Oct 2019 12:06:08 +0300 Subject: [PATCH 3/5] docs: add range variables --- docs/sources/reference/functions.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/sources/reference/functions.md b/docs/sources/reference/functions.md index be6305f..2dbc2a5 100644 --- a/docs/sources/reference/functions.md +++ b/docs/sources/reference/functions.md @@ -1,6 +1,21 @@ Functions reference =================== +## Functions Variables + +There are some built-in template variables available for using in functions: + +- `$__range_ms` - panel time range in ms +- `$__range_s` - panel time range in seconds +- `$__range` - panel time range, string representation (`30s`, `1m`, `1h`) +- `$__range_series` - invoke function over all series values + +Examples: +``` +groupBy($__range, avg) +percentile($__range_series, 95) - 95th percentile over all values +``` + ## Transform From bc1453e38499bb9f7da090f13f1dd17742428e3a Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 28 Oct 2019 12:14:11 +0300 Subject: [PATCH 4/5] docs: percentile reference --- docs/sources/reference/functions.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/sources/reference/functions.md b/docs/sources/reference/functions.md index 2dbc2a5..fe7e580 100644 --- a/docs/sources/reference/functions.md +++ b/docs/sources/reference/functions.md @@ -16,6 +16,8 @@ groupBy($__range, avg) percentile($__range_series, 95) - 95th percentile over all values ``` +--- + ## Transform @@ -25,7 +27,7 @@ percentile($__range_series, 95) - 95th percentile over all values groupBy(interval, function) ``` -Takes each timeseries and consolidate its points falled in given _interval_ into one point using _function_, which can be one of: _avg_, _min_, _max_, _median_. +Takes each timeseries and consolidate its points fallen in the given _interval_ into one point using _function_, which can be one of: _avg_, _min_, _max_, _median_. Examples: ``` @@ -139,7 +141,7 @@ Replaces `null` values with N aggregateBy(interval, function) ``` -Takes all timeseries and consolidate all its points falled in given _interval_ into one point using _function_, which can be one of: _avg_, _min_, _max_, _median_. +Takes all timeseries and consolidate all its points fallen in the given _interval_ into one point using _function_, which can be one of: _avg_, _min_, _max_, _median_. Examples: ``` @@ -157,6 +159,20 @@ This will add metrics together and return the sum at each datapoint. This method --- +### _percentile_ +``` +percentile(interval, N) +``` +Takes all timeseries and consolidate all its points fallen in the given _interval_ into one point by Nth percentile. + +Examples: +``` +percentile(1h, 99) +percentile($__range_series, 95) - 95th percentile over all values +``` + +--- + ### _average_ ``` average(interval) From bcbbc971527fbe9c96616b8070fcefb20b734994 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 28 Oct 2019 16:20:37 +0300 Subject: [PATCH 5/5] fix codespell --- .circleci/config.yml | 2 +- .codespell_ignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .codespell_ignore diff --git a/.circleci/config.yml b/.circleci/config.yml index cf7cda4..e790502 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -162,7 +162,7 @@ jobs: steps: - checkout - run: sudo pip install codespell - - run: codespell -S './.git*,./src/img*' -L que + - run: codespell -S './.git*,./src/img*' -L que --ignore-words=./.codespell_ignore workflows: version: 2 diff --git a/.codespell_ignore b/.codespell_ignore new file mode 100644 index 0000000..87b3610 --- /dev/null +++ b/.codespell_ignore @@ -0,0 +1 @@ +hist