Services refactor - using ES6 modules.

This commit is contained in:
Alexander Zobnin
2016-03-19 14:07:21 +03:00
parent d1c503e71a
commit e8b4a4319c
6 changed files with 780 additions and 792 deletions

View File

@@ -19,9 +19,11 @@ module.exports = function(grunt) {
'!**/module.js', '!**/module.js',
'!**/query.controller.js', '!**/query.controller.js',
'!**/utils.js', '!**/utils.js',
'!**/DataProcessor.js',
'!**/zabbixAPICore.service.js', '!**/zabbixAPICore.service.js',
'!**/zabbixAPI.service.js', '!**/zabbixAPI.service.js',
//'!**/dataProcessing.service.js', '!**/queryProcessor.service.js',
'!**/zabbixCache.service.js',
'!**/metricFunctions.js', '!**/metricFunctions.js',
'!**/*.scss' '!**/*.scss'
], ],
@@ -57,9 +59,11 @@ module.exports = function(grunt) {
'**/**/datasource.js', '**/**/datasource.js',
'**/**/query.controller.js', '**/**/query.controller.js',
'**/**/utils.js', '**/**/utils.js',
'**/**/DataProcessor.js',
'**/**/zabbixAPICore.service.js', '**/**/zabbixAPICore.service.js',
'**/**/zabbixAPI.service.js', '**/**/zabbixAPI.service.js',
//'**/**/dataProcessing.service.js', '**/**/queryProcessor.service.js',
'**/**/zabbixCache.service.js',
'**/**/metricFunctions.js' '**/**/metricFunctions.js'
], ],
dest: 'dist/' dest: 'dist/'

View File

@@ -0,0 +1,234 @@
import _ from 'lodash';
import * as utils from './utils';
export default class DataProcessor {
/**
* Downsample datapoints series
*/
static downsampleSeries(datapoints, time_to, ms_interval, func) {
var downsampledSeries = [];
var timeWindow = {
from: time_to * 1000 - ms_interval,
to: time_to * 1000
};
var points_sum = 0;
var points_num = 0;
var value_avg = 0;
var frame = [];
for (var i = datapoints.length - 1; i >= 0; i -= 1) {
if (timeWindow.from < datapoints[i][1] && datapoints[i][1] <= timeWindow.to) {
points_sum += datapoints[i][0];
points_num++;
frame.push(datapoints[i][0]);
}
else {
value_avg = points_num ? points_sum / points_num : 0;
if (func === "max") {
downsampledSeries.push([_.max(frame), timeWindow.to]);
}
else if (func === "min") {
downsampledSeries.push([_.min(frame), timeWindow.to]);
}
// avg by default
else {
downsampledSeries.push([value_avg, timeWindow.to]);
}
// Shift time window
timeWindow.to = timeWindow.from;
timeWindow.from -= ms_interval;
points_sum = 0;
points_num = 0;
frame = [];
// Process point again
i++;
}
}
return downsampledSeries.reverse();
}
/**
* Group points by given time interval
* datapoints: [[<value>, <unixtime>], ...]
*/
static groupBy(interval, groupByCallback, datapoints) {
var ms_interval = utils.parseInterval(interval);
// Calculate frame timestamps
var frames = _.groupBy(datapoints, function(point) {
// Calculate time for group of points
return Math.floor(point[1] / ms_interval) * ms_interval;
});
// frame: { '<unixtime>': [[<value>, <unixtime>], ...] }
// return [{ '<unixtime>': <value> }, { '<unixtime>': <value> }, ...]
var grouped = _.mapValues(frames, function(frame) {
var points = _.map(frame, function(point) {
return point[0];
});
return groupByCallback(points);
});
// Convert points to Grafana format
return sortByTime(_.map(grouped, function(value, timestamp) {
return [Number(value), Number(timestamp)];
}));
}
static sumSeries(timeseries) {
// Calculate new points for interpolation
var new_timestamps = _.uniq(_.map(_.flatten(timeseries, true), function(point) {
return point[1];
}));
new_timestamps = _.sortBy(new_timestamps);
var interpolated_timeseries = _.map(timeseries, function(series) {
var timestamps = _.map(series, function(point) {
return point[1];
});
var new_points = _.map(_.difference(new_timestamps, timestamps), function(timestamp) {
return [null, timestamp];
});
var new_series = series.concat(new_points);
return sortByTime(new_series);
});
_.each(interpolated_timeseries, interpolateSeries);
var new_timeseries = [];
var sum;
for (var i = new_timestamps.length - 1; i >= 0; i--) {
sum = 0;
for (var j = interpolated_timeseries.length - 1; j >= 0; j--) {
sum += interpolated_timeseries[j][i][0];
}
new_timeseries.push([sum, new_timestamps[i]]);
}
return sortByTime(new_timeseries);
}
static AVERAGE(values) {
var sum = 0;
_.each(values, function(value) {
sum += value;
});
return sum / values.length;
}
static MIN(values) {
return _.min(values);
}
static MAX(values) {
return _.max(values);
}
static MEDIAN(values) {
var sorted = _.sortBy(values);
return sorted[Math.floor(sorted.length / 2)];
}
static setAlias(alias, timeseries) {
timeseries.target = alias;
return timeseries;
}
static groupByWrapper(interval, groupFunc, datapoints) {
var groupByCallback = DataProcessor.aggregationFunctions[groupFunc];
return DataProcessor.groupBy(interval, groupByCallback, datapoints);
}
static aggregateWrapper(groupByCallback, interval, datapoints) {
var flattenedPoints = _.flatten(datapoints, true);
return DataProcessor.groupBy(interval, groupByCallback, flattenedPoints);
}
static get aggregationFunctions() {
return {
avg: this.AVERAGE,
min: this.MIN,
max: this.MAX,
median: this.MEDIAN
};
}
static get metricFunctions() {
return {
groupBy: this.groupByWrapper,
average: _.partial(this.aggregateWrapper, this.AVERAGE),
min: _.partial(this.aggregateWrapper, this.MIN),
max: _.partial(this.aggregateWrapper, this.MAX),
median: _.partial(this.aggregateWrapper, this.MEDIAN),
sumSeries: this.sumSeries,
setAlias: this.setAlias,
};
}
}
function sortByTime(series) {
return _.sortBy(series, function(point) {
return point[1];
});
}
/**
* Interpolate series with gaps
*/
function interpolateSeries(series) {
var left, right;
// Interpolate series
for (var i = series.length - 1; i >= 0; i--) {
if (!series[i][0]) {
left = findNearestLeft(series, series[i]);
right = findNearestRight(series, series[i]);
if (!left) {
left = right;
}
if (!right) {
right = left;
}
series[i][0] = linearInterpolation(series[i][1], left, right);
}
}
return series;
}
function linearInterpolation(timestamp, left, right) {
if (left[1] === right[1]) {
return (left[0] + right[0]) / 2;
} else {
return (left[0] + (right[0] - left[0]) / (right[1] - left[1]) * (timestamp - left[1]));
}
}
function findNearestRight(series, point) {
var point_index = _.indexOf(series, point);
var nearestRight;
for (var i = point_index; i < series.length; i++) {
if (series[i][0]) {
return series[i];
}
}
return nearestRight;
}
function findNearestLeft(series, point) {
var point_index = _.indexOf(series, point);
var nearestLeft;
for (var i = point_index; i > 0; i--) {
if (series[i][0]) {
return series[i];
}
}
return nearestLeft;
}

View File

@@ -1,241 +0,0 @@
define([
'angular',
'lodash',
'moment',
'./utils'
],
function (angular, _, moment, utils) {
'use strict';
var module = angular.module('grafana.services');
module.service('DataProcessingService', function() {
var self = this;
/**
* Downsample datapoints series
*/
this.downsampleSeries = function(datapoints, time_to, ms_interval, func) {
var downsampledSeries = [];
var timeWindow = {
from: time_to * 1000 - ms_interval,
to: time_to * 1000
};
var points_sum = 0;
var points_num = 0;
var value_avg = 0;
var frame = [];
for (var i = datapoints.length - 1; i >= 0; i -= 1) {
if (timeWindow.from < datapoints[i][1] && datapoints[i][1] <= timeWindow.to) {
points_sum += datapoints[i][0];
points_num++;
frame.push(datapoints[i][0]);
}
else {
value_avg = points_num ? points_sum / points_num : 0;
if (func === "max") {
downsampledSeries.push([_.max(frame), timeWindow.to]);
}
else if (func === "min") {
downsampledSeries.push([_.min(frame), timeWindow.to]);
}
// avg by default
else {
downsampledSeries.push([value_avg, timeWindow.to]);
}
// Shift time window
timeWindow.to = timeWindow.from;
timeWindow.from -= ms_interval;
points_sum = 0;
points_num = 0;
frame = [];
// Process point again
i++;
}
}
return downsampledSeries.reverse();
};
/**
* Group points by given time interval
* datapoints: [[<value>, <unixtime>], ...]
*/
this.groupBy = function(interval, groupByCallback, datapoints) {
var ms_interval = utils.parseInterval(interval);
// Calculate frame timestamps
var frames = _.groupBy(datapoints, function(point) {
// Calculate time for group of points
return Math.floor(point[1] / ms_interval) * ms_interval;
});
// frame: { '<unixtime>': [[<value>, <unixtime>], ...] }
// return [{ '<unixtime>': <value> }, { '<unixtime>': <value> }, ...]
var grouped = _.mapValues(frames, function(frame) {
var points = _.map(frame, function(point) {
return point[0];
});
return groupByCallback(points);
});
// Convert points to Grafana format
return sortByTime(_.map(grouped, function(value, timestamp) {
return [Number(value), Number(timestamp)];
}));
};
this.sumSeries = function(timeseries) {
// Calculate new points for interpolation
var new_timestamps = _.uniq(_.map(_.flatten(timeseries, true), function(point) {
return point[1];
}));
new_timestamps = _.sortBy(new_timestamps);
var interpolated_timeseries = _.map(timeseries, function(series) {
var timestamps = _.map(series, function(point) {
return point[1];
});
var new_points = _.map(_.difference(new_timestamps, timestamps), function(timestamp) {
return [null, timestamp];
});
var new_series = series.concat(new_points);
return sortByTime(new_series);
});
_.each(interpolated_timeseries, interpolateSeries);
var new_timeseries = [];
var sum;
for (var i = new_timestamps.length - 1; i >= 0; i--) {
sum = 0;
for (var j = interpolated_timeseries.length - 1; j >= 0; j--) {
sum += interpolated_timeseries[j][i][0];
}
new_timeseries.push([sum, new_timestamps[i]]);
}
return sortByTime(new_timeseries);
};
function sortByTime(series) {
return _.sortBy(series, function(point) {
return point[1];
});
}
/**
* Interpolate series with gaps
*/
function interpolateSeries(series) {
var left, right;
// Interpolate series
for (var i = series.length - 1; i >= 0; i--) {
if (!series[i][0]) {
left = findNearestLeft(series, series[i]);
right = findNearestRight(series, series[i]);
if (!left) {
left = right;
}
if (!right) {
right = left;
}
series[i][0] = linearInterpolation(series[i][1], left, right);
}
}
return series;
}
function linearInterpolation(timestamp, left, right) {
if (left[1] === right[1]) {
return (left[0] + right[0]) / 2;
} else {
return (left[0] + (right[0] - left[0]) / (right[1] - left[1]) * (timestamp - left[1]));
}
}
function findNearestRight(series, point) {
var point_index = _.indexOf(series, point);
var nearestRight;
for (var i = point_index; i < series.length; i++) {
if (series[i][0]) {
return series[i];
}
}
return nearestRight;
}
function findNearestLeft(series, point) {
var point_index = _.indexOf(series, point);
var nearestLeft;
for (var i = point_index; i > 0; i--) {
if (series[i][0]) {
return series[i];
}
}
return nearestLeft;
}
this.AVERAGE = function(values) {
var sum = 0;
_.each(values, function(value) {
sum += value;
});
return sum / values.length;
};
this.MIN = function(values) {
return _.min(values);
};
this.MAX = function(values) {
return _.max(values);
};
this.MEDIAN = function(values) {
var sorted = _.sortBy(values);
return sorted[Math.floor(sorted.length / 2)];
};
this.setAlias = function(alias, timeseries) {
timeseries.target = alias;
return timeseries;
};
this.aggregationFunctions = {
avg: this.AVERAGE,
min: this.MIN,
max: this.MAX,
median: this.MEDIAN
};
this.groupByWrapper = function(interval, groupFunc, datapoints) {
var groupByCallback = self.aggregationFunctions[groupFunc];
return self.groupBy(interval, groupByCallback, datapoints);
};
this.aggregateWrapper = function(groupByCallback, interval, datapoints) {
var flattenedPoints = _.flatten(datapoints, true);
return self.groupBy(interval, groupByCallback, flattenedPoints);
};
this.metricFunctions = {
groupBy: this.groupByWrapper,
average: _.partial(this.aggregateWrapper, this.AVERAGE),
min: _.partial(this.aggregateWrapper, this.MIN),
max: _.partial(this.aggregateWrapper, this.MAX),
median: _.partial(this.aggregateWrapper, this.MEDIAN),
sumSeries: this.sumSeries,
setAlias: this.setAlias,
};
});
});

View File

@@ -3,15 +3,15 @@ import _ from 'lodash';
import * as dateMath from 'app/core/utils/datemath'; import * as dateMath from 'app/core/utils/datemath';
import * as utils from './utils'; import * as utils from './utils';
import * as metricFunctions from './metricFunctions'; import * as metricFunctions from './metricFunctions';
import DataProcessor from './DataProcessor';
import './zabbixAPI.service.js'; import './zabbixAPI.service.js';
import './zabbixCache.service.js'; import './zabbixCache.service.js';
import './queryProcessor.service.js'; import './queryProcessor.service.js';
import './dataProcessing.service';
export class ZabbixAPIDatasource { export class ZabbixAPIDatasource {
/** @ngInject */ /** @ngInject */
constructor(instanceSettings, $q, templateSrv, alertSrv, zabbixAPIService, ZabbixCachingProxy, QueryProcessor, DataProcessingService) { constructor(instanceSettings, $q, templateSrv, alertSrv, zabbixAPIService, ZabbixCachingProxy, QueryProcessor) {
// General data source settings // General data source settings
this.name = instanceSettings.name; this.name = instanceSettings.name;
@@ -45,7 +45,6 @@ export class ZabbixAPIDatasource {
this.q = $q; this.q = $q;
this.templateSrv = templateSrv; this.templateSrv = templateSrv;
this.alertSrv = alertSrv; this.alertSrv = alertSrv;
this.DataProcessingService = DataProcessingService;
console.log(this.zabbixCache); console.log(this.zabbixCache);
} }
@@ -159,7 +158,7 @@ export class ZabbixAPIDatasource {
timeseries_data = _.map(timeseries_data, function (timeseries) { timeseries_data = _.map(timeseries_data, function (timeseries) {
// Filter only transform functions // Filter only transform functions
var transformFunctions = bindFunctionDefs(target.functions, 'Transform', self.DataProcessingService); var transformFunctions = bindFunctionDefs(target.functions, 'Transform', DataProcessor);
// Metric data processing // Metric data processing
var dp = timeseries.datapoints; var dp = timeseries.datapoints;
@@ -172,7 +171,7 @@ export class ZabbixAPIDatasource {
}); });
// Aggregations // Aggregations
var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate', self.DataProcessingService); var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate', DataProcessor);
var dp = _.map(timeseries_data, 'datapoints'); var dp = _.map(timeseries_data, 'datapoints');
if (aggregationFunctions.length) { if (aggregationFunctions.length) {
for (var i = 0; i < aggregationFunctions.length; i++) { for (var i = 0; i < aggregationFunctions.length; i++) {
@@ -189,7 +188,7 @@ export class ZabbixAPIDatasource {
} }
// Apply alias functions // Apply alias functions
var aliasFunctions = bindFunctionDefs(target.functions, 'Alias', self.DataProcessingService); var aliasFunctions = bindFunctionDefs(target.functions, 'Alias', DataProcessor);
for (var j = 0; j < aliasFunctions.length; j++) { for (var j = 0; j < aliasFunctions.length; j++) {
_.each(timeseries_data, aliasFunctions[j]); _.each(timeseries_data, aliasFunctions[j]);
} }
@@ -255,9 +254,9 @@ export class ZabbixAPIDatasource {
// Series downsampling // Series downsampling
var data = _.map(timeseries_data, function(timeseries) { var data = _.map(timeseries_data, function(timeseries) {
var DPS = self.DataProcessingService;
if (timeseries.datapoints.length > options.maxDataPoints) { if (timeseries.datapoints.length > options.maxDataPoints) {
timeseries.datapoints = DPS.groupBy(options.interval, DPS.AVERAGE, timeseries.datapoints); timeseries.datapoints =
DataProcessor.groupBy(options.interval, DataProcessor.AVERAGE, timeseries.datapoints);
} }
return timeseries; return timeseries;
}); });
@@ -409,7 +408,7 @@ export class ZabbixAPIDatasource {
} }
function bindFunctionDefs(functionDefs, category, DataProcessingService) { function bindFunctionDefs(functionDefs, category, DataProcessor) {
'use strict'; 'use strict';
var aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name'); var aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name');
var aggFuncDefs = _.filter(functionDefs, function(func) { var aggFuncDefs = _.filter(functionDefs, function(func) {
@@ -418,7 +417,7 @@ function bindFunctionDefs(functionDefs, category, DataProcessingService) {
return _.map(aggFuncDefs, function(func) { return _.map(aggFuncDefs, function(func) {
var funcInstance = metricFunctions.createFuncInstance(func.def, func.params); var funcInstance = metricFunctions.createFuncInstance(func.def, func.params);
return funcInstance.bindFunction(DataProcessingService.metricFunctions); return funcInstance.bindFunction(DataProcessor.metricFunctions);
}); });
} }

View File

@@ -1,57 +1,56 @@
define([ import angular from 'angular';
'angular', import _ from 'lodash';
'lodash', import * as utils from './utils';
'./utils'
],
function (angular, _, utils) {
'use strict';
var module = angular.module('grafana.services'); /** @ngInject */
angular.module('grafana.services').factory('QueryProcessor', function($q) {
module.factory('QueryProcessor', function($q) {
function QueryProcessor(zabbixCacheInstance) {
var self = this;
class QueryProcessor {
constructor(zabbixCacheInstance) {
this.cache = zabbixCacheInstance; this.cache = zabbixCacheInstance;
this.$q = $q;
}
/** /**
* Build query in asynchronous manner * Build query in asynchronous manner
*/ */
this.build = function (groupFilter, hostFilter, appFilter, itemFilter) { build(groupFilter, hostFilter, appFilter, itemFilter) {
var self = this;
if (this.cache._initialized) { if (this.cache._initialized) {
return $q.when(self.buildFromCache(groupFilter, hostFilter, appFilter, itemFilter)); return this.$q.when(self.buildFromCache(groupFilter, hostFilter, appFilter, itemFilter));
} else { } else {
return this.cache.refresh().then(function() { return this.cache.refresh().then(function() {
return self.buildFromCache(groupFilter, hostFilter, appFilter, itemFilter); return self.buildFromCache(groupFilter, hostFilter, appFilter, itemFilter);
}); });
} }
}; }
/** /**
* Build trigger query in asynchronous manner * Build trigger query in asynchronous manner
*/ */
this.buildTriggerQuery = function (groupFilter, hostFilter, appFilter) { buildTriggerQuery(groupFilter, hostFilter, appFilter) {
var self = this;
if (this.cache._initialized) { if (this.cache._initialized) {
return $q.when(self.buildTriggerQueryFromCache(groupFilter, hostFilter, appFilter)); return this.$q.when(self.buildTriggerQueryFromCache(groupFilter, hostFilter, appFilter));
} else { } else {
return this.cache.refresh().then(function() { return this.cache.refresh().then(function() {
return self.buildTriggerQueryFromCache(groupFilter, hostFilter, appFilter); return self.buildTriggerQueryFromCache(groupFilter, hostFilter, appFilter);
}); });
} }
}; }
this.filterGroups = function(groupFilter) { filterGroups(groupFilter) {
return this.cache.getGroups().then(function(groupList) { return this.cache.getGroups().then(function(groupList) {
return groupList; return groupList;
}); });
}; }
/** /**
* Get list of host belonging to given groups. * Get list of host belonging to given groups.
* @return list of hosts * @return list of hosts
*/ */
this.filterHosts = function(groupFilter) { filterHosts(groupFilter) {
var self = this;
return this.cache.getGroups().then(function(groups) { return this.cache.getGroups().then(function(groups) {
groups = findByFilter(groups, groupFilter); groups = findByFilter(groups, groupFilter);
var hostids = _.flatten(_.map(groups, 'hosts')); var hostids = _.flatten(_.map(groups, 'hosts'));
@@ -65,19 +64,19 @@ function (angular, _, utils) {
return []; return [];
} }
}); });
}; }
/** /**
* Get list of applications belonging to given groups and hosts. * Get list of applications belonging to given groups and hosts.
* @return list of applications belonging to given hosts * @return list of applications belonging to given hosts
*/ */
this.filterApplications = function(groupFilter, hostFilter) { filterApplications(groupFilter, hostFilter) {
var promises = [ var promises = [
this.filterHosts(groupFilter), this.filterHosts(groupFilter),
this.cache.getApplications() this.cache.getApplications()
]; ];
return $q.all(promises).then(function(results) { return this.$q.all(promises).then(function(results) {
var hostList = results[0]; var hostList = results[0];
var applicationList = results[1]; var applicationList = results[1];
@@ -91,9 +90,9 @@ function (angular, _, utils) {
return []; return [];
} }
}); });
}; }
this.filterItems = function (groupFilter, hostFilter, appFilter, itemType, showDisabledItems) { filterItems(groupFilter, hostFilter, appFilter, itemType, showDisabledItems) {
var hosts; var hosts;
var apps; var apps;
var items; var items;
@@ -105,7 +104,7 @@ function (angular, _, utils) {
this.cache.getIndexedApplications() this.cache.getIndexedApplications()
]; ];
return $q.all(promises).then(function(results) { return this.$q.all(promises).then(function(results) {
var hostList = results[0]; var hostList = results[0];
var applicationList = results[1]; var applicationList = results[1];
var idx_hosts = results[2]; var idx_hosts = results[2];
@@ -150,12 +149,12 @@ function (angular, _, utils) {
return items; return items;
}); });
}; }
/** /**
* Build query - convert target filters to array of Zabbix items * Build query - convert target filters to array of Zabbix items
*/ */
this.buildFromCache = function (groupFilter, hostFilter, appFilter, itemFilter) { buildFromCache(groupFilter, hostFilter, appFilter, itemFilter) {
return this.filterItems(groupFilter, hostFilter, appFilter).then(function(items) { return this.filterItems(groupFilter, hostFilter, appFilter).then(function(items) {
if (items.length) { if (items.length) {
if (utils.isRegex(itemFilter)) { if (utils.isRegex(itemFilter)) {
@@ -167,12 +166,12 @@ function (angular, _, utils) {
return []; return [];
} }
}); });
}; }
/** /**
* Build query - convert target filters to array of Zabbix items * Build query - convert target filters to array of Zabbix items
*/ */
this.buildTriggerQueryFromCache = function (groupFilter, hostFilter, appFilter) { buildTriggerQueryFromCache(groupFilter, hostFilter, appFilter) {
var promises = [ var promises = [
this.cache.getGroups().then(function(groups) { this.cache.getGroups().then(function(groups) {
return _.filter(groups, function(group) { return _.filter(groups, function(group) {
@@ -203,7 +202,7 @@ function (angular, _, utils) {
}) })
]; ];
return $q.all(promises).then(function(results) { return this.$q.all(promises).then(function(results) {
var filteredGroups = results[0]; var filteredGroups = results[0];
var filteredHosts = results[1]; var filteredHosts = results[1];
var filteredApps = results[2]; var filteredApps = results[2];
@@ -221,7 +220,7 @@ function (angular, _, utils) {
return query; return query;
}); });
}; }
/** /**
* Convert Zabbix API history.get response to Grafana format * Convert Zabbix API history.get response to Grafana format
@@ -232,7 +231,7 @@ function (angular, _, utils) {
* datapoints: [[<value>, <unixtime>], ...] * datapoints: [[<value>, <unixtime>], ...]
* } * }
*/ */
this.convertHistory = function(history, addHostName, convertPointCallback) { convertHistory(history, addHostName, convertPointCallback) {
/** /**
* Response should be in the format: * Response should be in the format:
* data: [ * data: [
@@ -242,6 +241,7 @@ function (angular, _, utils) {
* }, ... * }, ...
* ] * ]
*/ */
var self = this;
// Group history by itemid // Group history by itemid
var grouped_history = _.groupBy(history, 'itemid'); var grouped_history = _.groupBy(history, 'itemid');
@@ -258,18 +258,18 @@ function (angular, _, utils) {
datapoints: _.map(hist, convertPointCallback) datapoints: _.map(hist, convertPointCallback)
}; };
}); });
}; }
this.handleHistory = function(history, addHostName) { handleHistory(history, addHostName) {
return this.convertHistory(history, addHostName, convertHistoryPoint); return this.convertHistory(history, addHostName, convertHistoryPoint);
}; }
this.handleTrends = function(history, addHostName, valueType) { handleTrends(history, addHostName, valueType) {
var convertPointCallback = _.partial(convertTrendPoint, valueType); var convertPointCallback = _.partial(convertTrendPoint, valueType);
return this.convertHistory(history, addHostName, convertPointCallback); return this.convertHistory(history, addHostName, convertPointCallback);
}; }
this.handleSLAResponse = function (itservice, slaProperty, slaObject) { handleSLAResponse(itservice, slaProperty, slaObject) {
var targetSLA = slaObject[itservice.serviceid].sla[0]; var targetSLA = slaObject[itservice.serviceid].sla[0];
if (slaProperty.property === 'status') { if (slaProperty.property === 'status') {
var targetStatus = parseInt(slaObject[itservice.serviceid].status); var targetStatus = parseInt(slaObject[itservice.serviceid].status);
@@ -288,57 +288,57 @@ function (angular, _, utils) {
] ]
}; };
} }
}; }
} }
return QueryProcessor; return QueryProcessor;
}); });
/** /**
* Find group, host, app or item by given name. * Find group, host, app or item by given name.
* @param list list of groups, apps or other * @param list list of groups, apps or other
* @param name visible name * @param name visible name
* @return array with finded element or undefined * @return array with finded element or undefined
*/ */
function findByName(list, name) { function findByName(list, name) {
var finded = _.find(list, {'name': name}); var finded = _.find(list, {'name': name});
if (finded) { if (finded) {
return [finded]; return [finded];
} else { } else {
return undefined; return undefined;
} }
} }
function findByRegex(list, regex) { function findByRegex(list, regex) {
var filterPattern = utils.buildRegex(regex); var filterPattern = utils.buildRegex(regex);
return _.filter(list, function (zbx_obj) { return _.filter(list, function (zbx_obj) {
return filterPattern.test(zbx_obj.name); return filterPattern.test(zbx_obj.name);
}); });
} }
function findByFilter(list, filter) { function findByFilter(list, filter) {
if (utils.isRegex(filter)) { if (utils.isRegex(filter)) {
return findByRegex(list, filter); return findByRegex(list, filter);
} else { } else {
return findByName(list, filter); return findByName(list, filter);
} }
} }
function getFromIndex(index, objids) { function getFromIndex(index, objids) {
return _.map(objids, function(id) { return _.map(objids, function(id) {
return index[id]; return index[id];
}); });
} }
function convertHistoryPoint(point) { function convertHistoryPoint(point) {
// Value must be a number for properly work // Value must be a number for properly work
return [ return [
Number(point.value), Number(point.value),
point.clock * 1000 point.clock * 1000
]; ];
} }
function convertTrendPoint(valueType, point) { function convertTrendPoint(valueType, point) {
var value; var value;
switch (valueType) { switch (valueType) {
case "min": case "min":
@@ -358,6 +358,4 @@ function (angular, _, utils) {
Number(value), Number(value),
point.clock * 1000 point.clock * 1000
]; ];
} }
});

View File

@@ -1,27 +1,25 @@
define([ import angular from 'angular';
'angular', import _ from 'lodash';
'lodash', import * as utils from './utils';
'./utils'
],
function (angular, _, utils) {
'use strict';
var module = angular.module('grafana.services'); // Use factory() instead service() for multiple datasources support.
// Each datasource instance must initialize its own cache.
// Use factory() instead service() for multiple datasources support. /** @ngInject */
// Each datasource instance must initialize its own cache. angular.module('grafana.services').factory('ZabbixCachingProxy', function($q, $interval) {
module.factory('ZabbixCachingProxy', function($q, $interval) {
function ZabbixCachingProxy(zabbixAPI, ttl) { class ZabbixCachingProxy {
constructor(zabbixAPI, ttl) {
this.zabbixAPI = zabbixAPI; this.zabbixAPI = zabbixAPI;
this.ttl = ttl; this.ttl = ttl;
this.$q = $q;
// Internal objects for data storing // Internal objects for data storing
this._groups = undefined; this._groups = undefined;
this._hosts = undefined; this._hosts = undefined;
this._applications = undefined; this._applications = undefined;
this._items = undefined; this._items = undefined;
this._hostsExtend = undefined;
this.storage = { this.storage = {
history: {}, history: {},
trends: {} trends: {}
@@ -34,7 +32,7 @@ function (angular, _, utils) {
this.historyPromises = {}; this.historyPromises = {};
// Wrap _refresh() method to call it once. // Wrap _refresh() method to call it once.
this.refresh = callOnce(p._refresh, this.refreshPromise); this.refresh = callOnce(this._refresh, this.refreshPromise);
// Update cache periodically // Update cache periodically
$interval(_.bind(this.refresh, this), this.ttl); $interval(_.bind(this.refresh, this), this.ttl);
@@ -44,9 +42,7 @@ function (angular, _, utils) {
this.historyPromises); this.historyPromises);
} }
var p = ZabbixCachingProxy.prototype; _refresh() {
p._refresh = function() {
var self = this; var self = this;
var promises = [ var promises = [
this.zabbixAPI.getGroups(), this.zabbixAPI.getGroups(),
@@ -56,7 +52,7 @@ function (angular, _, utils) {
this.zabbixAPI.getHostsExtend() this.zabbixAPI.getHostsExtend()
]; ];
return $q.all(promises).then(function(results) { return this.$q.all(promises).then(function(results) {
if (results.length) { if (results.length) {
self._groups = convertGroups(results[0]); self._groups = convertGroups(results[0]);
self._hosts = convertHosts(results[1]); self._hosts = convertHosts(results[1]);
@@ -67,94 +63,76 @@ function (angular, _, utils) {
} }
self._initialized = true; self._initialized = true;
}); });
}; }
p.getGroups = function() { getGroups() {
var self = this; var self = this;
if (this._groups) { if (this._groups) {
return $q.when(self._groups); return this.$q.when(self._groups);
} else { } else {
return this.refresh().then(function() { return this.refresh().then(function() {
return self._groups; return self._groups;
}); });
} }
}; }
p.getHosts = function() { getHosts() {
var self = this; var self = this;
if (this._hosts) { if (this._hosts) {
return $q.when(self._hosts); return this.$q.when(self._hosts);
} else { } else {
return this.refresh().then(function() { return this.refresh().then(function() {
return self._hosts; return self._hosts;
}); });
} }
}; }
p.getIndexedHosts = function() { getIndexedHosts() {
var self = this; var self = this;
if (this._idx_hosts) { if (this._idx_hosts) {
return $q.when(self._idx_hosts); return this.$q.when(self._idx_hosts);
} else { } else {
return this.refresh().then(function() { return this.refresh().then(function() {
return self._idx_hosts; return self._idx_hosts;
}); });
} }
}; }
p.getIndexedApplications = function() { getIndexedApplications() {
var self = this; var self = this;
if (this._idx_apps) { if (this._idx_apps) {
return $q.when(self._idx_apps); return this.$q.when(self._idx_apps);
} else { } else {
return this.refresh().then(function() { return this.refresh().then(function() {
return self._idx_apps; return self._idx_apps;
}); });
} }
}; }
p.getApplications = function() { getApplications() {
var self = this; var self = this;
if (this._applications) { if (this._applications) {
return $q.when(self._applications); return this.$q.when(self._applications);
} else { } else {
return this.refresh().then(function() { return this.refresh().then(function() {
return self._applications; return self._applications;
}); });
} }
}; }
p.getItems = function(type) { getItems(type) {
var self = this; var self = this;
if (this._items) { if (this._items) {
return $q.when(filterItems(self._items, type)); return this.$q.when(filterItems(self._items, type));
} else { } else {
return this.refresh().then(function() { return this.refresh().then(function() {
return filterItems(self._items, type); return filterItems(self._items, type);
}); });
} }
};
function filterItems(items, type) {
switch (type) {
case 'num':
return _.filter(items, function(item) {
return (item.value_type === '0' ||
item.value_type === '3');
});
case 'text':
return _.filter(items, function(item) {
return (item.value_type === '1' ||
item.value_type === '2' ||
item.value_type === '4');
});
default:
return items;
}
} }
p.getHistoryFromCache = function(items, time_from, time_till) { getHistoryFromCache(items, time_from, time_till) {
var deferred = $q.defer(); var deferred = this.$q.defer();
var historyStorage = this.storage.history; var historyStorage = this.storage.history;
var full_history; var full_history;
var expired = _.filter(_.indexBy(items, 'itemid'), function(item, itemid) { var expired = _.filter(_.indexBy(items, 'itemid'), function(item, itemid) {
@@ -182,123 +160,21 @@ function (angular, _, utils) {
deferred.resolve(_.flatten(full_history, true)); deferred.resolve(_.flatten(full_history, true));
} }
return deferred.promise; return deferred.promise;
}; }
p.getHistoryFromAPI = function(items, time_from, time_till) { getHistoryFromAPI(items, time_from, time_till) {
return this.zabbixAPI.getHistory(items, time_from, time_till); return this.zabbixAPI.getHistory(items, time_from, time_till);
}; }
p.getHost = function(hostid) { getHost(hostid) {
return _.find(this._hosts, {'hostid': hostid}); return _.find(this._hosts, {'hostid': hostid});
}; }
p.getItem = function(itemid) { getItem(itemid) {
return _.find(this._items, {'itemid': itemid}); return _.find(this._items, {'itemid': itemid});
};
/**
* Convert host.get response to cache format
* host.groups - array of group ids
*/
function convertHosts(hosts) {
return _.forEach(hosts, function(host) {
host.groups = _.map(host.groups, 'groupid');
return host;
});
} }
function convertGroups(groups) {
return _.forEach(groups, function(group) {
group.hosts = _.map(group.hosts, 'hostid');
return group;
});
} }
/**
* Group Zabbix applications by name
* host.hosts - array of host ids
*/
function convertApplications(applications) {
return _.map(_.groupBy(applications, 'name'), function(value, key) {
//console.log(value);
// Hack for supporting different apis (2.2 vs 2.4 vs 3.0)
var hostField = 'host';
if (value[0] && value[0]['hosts']) {
// For Zabbix 2.2
hostField = 'hosts';
}
return {
name: key,
applicationids: _.map(value, 'applicationid'),
itemids: _.uniq(_.map(_.flatten(value, 'items'), 'itemid')),
hosts: _.uniq(_.map(_.flatten(value, hostField), 'hostid'))
};
});
}
function indexHosts(hosts) {
return _.indexBy(_.map(hosts, function(host) {
// Expand item names
host.items = _.forEach(host.items, function(item) {
item.item = item.name;
item.name = utils.expandItemName(item.item, item.key_);
return item;
});
host.applications = _.map(host.applications, 'applicationid');
host.idx_items = indexItems(host.items);
host.items = _.map(host.items, 'itemid');
return host;
}), 'hostid');
}
function indexApps(applications) {
return _.indexBy(_.map(applications, function(app) {
return {
name: app.name,
applicationid: app.applicationid,
host: _.first(_.map(app.hosts, 'hostid')),
itemids: _.map(app.items, 'itemid')
};
}), 'applicationid');
}
function indexItems(items) {
return _.indexBy(_.map(items, function(item) {
return item;
}), 'itemid');
}
/**
* Convert item.get response to cache format
* item.applications - array of application ids
* item.item - original item name returned by api (ie "CPU $2 time")
* item.name - expanded name (ie "CPU system time")
*/
function convertItems(items) {
return _.forEach(items, function(item) {
item.applications = _.map(item.applications, 'applicationid');
item.item = item.name;
item.name = utils.expandItemName(item.item, item.key_);
return item;
});
}
String.prototype.getHash = function() {
var hash = 0, i, chr, len;
if (this.length === 0) {
return hash;
}
for (i = 0, len = this.length; i < len; i++) {
chr = this.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
function callHistoryOnce(func, promiseKeeper) { function callHistoryOnce(func, promiseKeeper) {
return function() { return function() {
var itemids = _.map(arguments[0], 'itemid'); var itemids = _.map(arguments[0], 'itemid');
@@ -336,7 +212,125 @@ function (angular, _, utils) {
} }
return ZabbixCachingProxy; return ZabbixCachingProxy;
});
/**
* Convert host.get response to cache format
* host.groups - array of group ids
*/
function convertHosts(hosts) {
return _.forEach(hosts, function(host) {
host.groups = _.map(host.groups, 'groupid');
return host;
});
}
function convertGroups(groups) {
return _.forEach(groups, function(group) {
group.hosts = _.map(group.hosts, 'hostid');
return group;
});
}
/**
* Group Zabbix applications by name
* host.hosts - array of host ids
*/
function convertApplications(applications) {
return _.map(_.groupBy(applications, 'name'), function(value, key) {
//console.log(value);
// Hack for supporting different apis (2.2 vs 2.4 vs 3.0)
var hostField = 'host';
if (value[0] && value[0]['hosts']) {
// For Zabbix 2.2
hostField = 'hosts';
}
return {
name: key,
applicationids: _.map(value, 'applicationid'),
itemids: _.uniq(_.map(_.flatten(value, 'items'), 'itemid')),
hosts: _.uniq(_.map(_.flatten(value, hostField), 'hostid'))
};
});
}
function indexHosts(hosts) {
return _.indexBy(_.map(hosts, function(host) {
// Expand item names
host.items = _.forEach(host.items, function(item) {
item.item = item.name;
item.name = utils.expandItemName(item.item, item.key_);
return item;
}); });
}); host.applications = _.map(host.applications, 'applicationid');
host.idx_items = indexItems(host.items);
host.items = _.map(host.items, 'itemid');
return host;
}), 'hostid');
}
function indexApps(applications) {
return _.indexBy(_.map(applications, function(app) {
return {
name: app.name,
applicationid: app.applicationid,
host: _.first(_.map(app.hosts, 'hostid')),
itemids: _.map(app.items, 'itemid')
};
}), 'applicationid');
}
function indexItems(items) {
return _.indexBy(_.map(items, function(item) {
return item;
}), 'itemid');
}
/**
* Convert item.get response to cache format
* item.applications - array of application ids
* item.item - original item name returned by api (ie "CPU $2 time")
* item.name - expanded name (ie "CPU system time")
*/
function convertItems(items) {
return _.forEach(items, function(item) {
item.applications = _.map(item.applications, 'applicationid');
item.item = item.name;
item.name = utils.expandItemName(item.item, item.key_);
return item;
});
}
function filterItems(items, type) {
switch (type) {
case 'num':
return _.filter(items, function(item) {
return (item.value_type === '0' ||
item.value_type === '3');
});
case 'text':
return _.filter(items, function(item) {
return (item.value_type === '1' ||
item.value_type === '2' ||
item.value_type === '4');
});
default:
return items;
}
}
String.prototype.getHash = function() {
var hash = 0, i, chr, len;
if (this.length === 0) {
return hash;
}
for (i = 0, len = this.length; i < len; i++) {
chr = this.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};