diff --git a/src/datasource-zabbix/dataProcessor.js b/src/datasource-zabbix/dataProcessor.js index dd299b3..0415d11 100644 --- a/src/datasource-zabbix/dataProcessor.js +++ b/src/datasource-zabbix/dataProcessor.js @@ -251,6 +251,23 @@ function findNearestLeft(series, point) { return nearestLeft; } +function timeShift(interval, range) { + let shift = utils.parseTimeShiftInterval(interval) / 1000; + return range.map(time => { + return time - shift; + }); +} + +function unShiftTimeSeries(interval, datapoints) { + let unshift = utils.parseTimeShiftInterval(interval); + return datapoints.map(dp => { + return [ + dp[0], + dp[1] + unshift + ]; + }); +} + let metricFunctions = { groupBy: groupByWrapper, scale: scale, @@ -263,6 +280,7 @@ let metricFunctions = { sumSeries: sumSeries, top: _.partial(limit, 'top'), bottom: _.partial(limit, 'bottom'), + timeShift: timeShift, setAlias: setAlias }; @@ -280,6 +298,7 @@ export default { MIN: MIN, MAX: MAX, MEDIAN: MEDIAN, + unShiftTimeSeries: unShiftTimeSeries, get aggregationFunctions() { return aggregationFunctions; diff --git a/src/datasource-zabbix/datasource.js b/src/datasource-zabbix/datasource.js index f4867e1..806442b 100644 --- a/src/datasource-zabbix/datasource.js +++ b/src/datasource-zabbix/datasource.js @@ -50,18 +50,26 @@ class ZabbixAPIDatasource { * @return {Object} Grafana metrics object with timeseries data for each target. */ query(options) { - var timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000); - var timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000); + let timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000); + let timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000); - var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000); - var useTrends = (timeFrom <= useTrendsFrom) && this.trends; + let useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000); + let useTrends = (timeFrom <= useTrendsFrom) && this.trends; // Create request for each target - var promises = _.map(options.targets, target => { + let promises = _.map(options.targets, target => { // Prevent changes of original object target = _.cloneDeep(target); this.replaceTargetVariables(target, options); + // Apply Time-related functions (timeShift(), etc) + let timeFunctions = bindFunctionDefs(target.functions, 'Time'); + if (timeFunctions.length) { + const [time_from, time_to] = sequence(timeFunctions)([timeFrom, timeTo]); + timeFrom = time_from; + timeTo = time_to; + } + // Metrics or Text query mode if (target.mode !== 1) { // Migrate old targets @@ -175,11 +183,28 @@ class ZabbixAPIDatasource { } // Apply alias functions - _.each(timeseries_data, sequence(aliasFunctions)); + _.forEach(timeseries_data, sequence(aliasFunctions)); + + // Apply Time-related functions (timeShift(), etc) + // Find timeShift() function and get specified trend value + this.applyTimeShiftFunction(timeseries_data, target); return timeseries_data; } + applyTimeShiftFunction(timeseries_data, target) { + // Find timeShift() function and get specified interval + let timeShiftFunc = _.find(target.functions, (func) => { + return func.def.name === 'timeShift'; + }); + if (timeShiftFunc) { + let shift = timeShiftFunc.params[0]; + _.forEach(timeseries_data, (series) => { + series.datapoints = dataProcessor.unShiftTimeSeries(shift, series.datapoints); + }); + } + } + queryTextData(target, timeFrom, timeTo) { let options = { itemtype: 'text' diff --git a/src/datasource-zabbix/metricFunctions.js b/src/datasource-zabbix/metricFunctions.js index 5d467f4..97e5c29 100644 --- a/src/datasource-zabbix/metricFunctions.js +++ b/src/datasource-zabbix/metricFunctions.js @@ -7,6 +7,7 @@ var categories = { Aggregate: [], Filter: [], Trends: [], + Time: [], Alias: [] }; @@ -21,6 +22,8 @@ function addFuncDef(funcDef) { index[funcDef.shortName || funcDef.name] = funcDef; } +// Transform + addFuncDef({ name: 'groupBy', category: 'Transform', @@ -47,6 +50,8 @@ addFuncDef({ defaultParams: [], }); +// Aggregate + addFuncDef({ name: 'sumSeries', category: 'Aggregate', @@ -100,6 +105,8 @@ addFuncDef({ defaultParams: ['1m', 'avg'], }); +// Filter + addFuncDef({ name: 'top', category: 'Filter', @@ -120,6 +127,8 @@ addFuncDef({ defaultParams: [5, 'avg'], }); +// Trends + addFuncDef({ name: 'trendValue', category: 'Trends', @@ -129,6 +138,17 @@ addFuncDef({ defaultParams: ['avg'], }); +// Time + +addFuncDef({ + name: 'timeShift', + category: 'Time', + params: [ + { name: 'interval', type: 'string', options: ['24h', '7d', '1M', '+24h', '-24h']} + ], + defaultParams: ['24h'], +}); + addFuncDef({ name: 'setAlias', category: 'Alias', diff --git a/src/datasource-zabbix/utils.js b/src/datasource-zabbix/utils.js index c410d57..7f7c15b 100644 --- a/src/datasource-zabbix/utils.js +++ b/src/datasource-zabbix/utils.js @@ -59,6 +59,20 @@ export function parseInterval(interval) { return moment.duration(Number(momentInterval[1]), momentInterval[2]).valueOf(); } +export function parseTimeShiftInterval(interval) { + let intervalPattern = /^([\+\-]*)([\d]+)(y|M|w|d|h|m|s)/g; + let momentInterval = intervalPattern.exec(interval); + let duration = 0; + + if (momentInterval[1] === '+') { + duration = 0 - moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf(); + } else { + duration = moment.duration(Number(momentInterval[2]), momentInterval[3]).valueOf(); + } + + return duration; +} + /** * Format acknowledges. *