diff --git a/plugins/datasource-zabbix/datasource.js b/plugins/datasource-zabbix/datasource.js index e25349d..f5e62c1 100644 --- a/plugins/datasource-zabbix/datasource.js +++ b/plugins/datasource-zabbix/datasource.js @@ -9,12 +9,12 @@ define([ './zabbixCache', './queryCtrl' ], -function (angular, _, dateMath, QueryBuilder) { +function (angular, _, dateMath) { 'use strict'; /** @ngInject */ function ZabbixAPIDatasource(instanceSettings, $q, templateSrv, alertSrv, - ZabbixAPI, zabbixHelperSrv, ZabbixCache) { + ZabbixAPI, zabbixHelperSrv, ZabbixCache, QueryBuilder) { // General data source settings this.name = instanceSettings.name; @@ -39,6 +39,8 @@ function (angular, _, dateMath, QueryBuilder) { // Initialize query builder this.queryBuilder = new QueryBuilder(this.zabbixCache); + console.log(this.zabbixCache); + //////////////////////// // Datasource methods // //////////////////////// @@ -128,19 +130,26 @@ function (angular, _, dateMath, QueryBuilder) { alias = templateSrv.replace(target.alias, options.scopedVars); } - var history; + // Add hostname for items from multiple hosts + var addHostName = target.host.isRegex; + + var getHistory; if ((from < useTrendsFrom) && self.trends) { + // Use trends - var points = target.downsampleFunction ? target.downsampleFunction.value : "avg"; - history = self.zabbixAPI.getTrends(items, from, to) - .then(_.bind(zabbixHelperSrv.handleTrendResponse, zabbixHelperSrv, items, alias, target.scale, points)); + var valueType = target.downsampleFunction ? target.downsampleFunction.value : "avg"; + getHistory = self.zabbixAPI.getTrends(items, from, to).then(function(history) { + return self.queryBuilder.handleTrends(history, addHostName, valueType); + }); } else { + // Use history - history = self.zabbixAPI.getHistory(items, from, to) - .then(_.bind(zabbixHelperSrv.handleHistoryResponse, zabbixHelperSrv, items, alias, target.scale)); + getHistory = self.zabbixAPI.getHistory(items, from, to).then(function(history) { + return self.queryBuilder.handleHistory(history, addHostName); + }); } - return history.then(function (timeseries) { + return getHistory.then(function (timeseries) { var timeseries_data = _.flatten(timeseries); return _.map(timeseries_data, function (timeseries) { diff --git a/plugins/datasource-zabbix/queryBuilder.js b/plugins/datasource-zabbix/queryBuilder.js index 8bdba8a..053ecf8 100644 --- a/plugins/datasource-zabbix/queryBuilder.js +++ b/plugins/datasource-zabbix/queryBuilder.js @@ -6,122 +6,206 @@ define([ function (angular, _, utils) { 'use strict'; - function QueryBuilder(zabbixCacheInstance) { + var module = angular.module('grafana.services'); - this.cache = zabbixCacheInstance; + module.factory('QueryBuilder', function() { - this.build = function (groupFilter, hostFilter, appFilter, itemFilter) { + function QueryBuilder(zabbixCacheInstance) { + var self = this; - // Find items by item names and perform queries - var groups = []; - var hosts = []; - var apps = []; - var items = []; + this.cache = zabbixCacheInstance; - if (utils.isRegex(hostFilter)) { + /** + * Build query - convert target filters to array of Zabbix items + */ + this.build = function (groupFilter, hostFilter, appFilter, itemFilter) { - // Filter groups - if (utils.isRegex(groupFilter)) { - var groupPattern = utils.buildRegex(groupFilter); - groups = _.filter(this.cache.getGroups(), function (groupObj) { - return groupPattern.test(groupObj.name); - }); - } else { - var findedGroup = _.find(this.cache.getGroups(), {'name': groupFilter}); - if (findedGroup) { - groups.push(findedGroup); + // Find items by item names and perform queries + var groups = []; + var hosts = []; + var apps = []; + var items = []; + + if (utils.isRegex(hostFilter)) { + + // Filter groups + if (utils.isRegex(groupFilter)) { + var groupPattern = utils.buildRegex(groupFilter); + groups = _.filter(this.cache.getGroups(), function (groupObj) { + return groupPattern.test(groupObj.name); + }); } else { - groups = undefined; + var findedGroup = _.find(this.cache.getGroups(), {'name': groupFilter}); + if (findedGroup) { + groups.push(findedGroup); + } else { + groups = undefined; + } } - } - if (groups) { - var groupids = _.map(groups, 'groupid'); - hosts = _.filter(this.cache.getHosts(), function (hostObj) { - return _.intersection(groupids, hostObj.groups).length; - }); - } else { - // No groups finded - return []; - } - - // Filter hosts - var hostPattern = utils.buildRegex(hostFilter); - hosts = _.filter(hosts, function (hostObj) { - return hostPattern.test(hostObj.name); - }); - } else { - var findedHost = _.find(this.cache.getHosts(), {'name': hostFilter}); - if (findedHost) { - hosts.push(findedHost); - } else { - // No hosts finded - return []; - } - } - - // Find items belongs to selected hosts - items = _.filter(this.cache.getItems(), function (itemObj) { - return _.contains(_.map(hosts, 'hostid'), itemObj.hostid); - }); - - if (utils.isRegex(itemFilter)) { - - // Filter applications - if (utils.isRegex(appFilter)) { - var appPattern = utils.buildRegex(appFilter); - apps = _.filter(this.cache.getApplications(), function (appObj) { - return appPattern.test(appObj.name); - }); - } - // Don't use application filter if it empty - else if (appFilter === "") { - apps = undefined; - } - else { - var findedApp = _.find(this.cache.getApplications(), {'name': appFilter}); - if (findedApp) { - apps.push(findedApp); + if (groups) { + var groupids = _.map(groups, 'groupid'); + hosts = _.filter(this.cache.getHosts(), function (hostObj) { + return _.intersection(groupids, hostObj.groups).length; + }); } else { - // No applications finded + // No groups finded + return []; + } + + // Filter hosts + var hostPattern = utils.buildRegex(hostFilter); + hosts = _.filter(hosts, function (hostObj) { + return hostPattern.test(hostObj.name); + }); + } else { + var findedHost = _.find(this.cache.getHosts(), {'name': hostFilter}); + if (findedHost) { + hosts.push(findedHost); + } else { + // No hosts finded return []; } } - // Find items belongs to selected applications - if (apps) { - var appids = _.flatten(_.map(apps, 'applicationids')); - items = _.filter(items, function (itemObj) { - return _.intersection(appids, itemObj.applications).length; - }); + // Find items belongs to selected hosts + items = _.filter(this.cache.getItems(), function (itemObj) { + return _.contains(_.map(hosts, 'hostid'), itemObj.hostid); + }); + + if (utils.isRegex(itemFilter)) { + + // Filter applications + if (utils.isRegex(appFilter)) { + var appPattern = utils.buildRegex(appFilter); + apps = _.filter(this.cache.getApplications(), function (appObj) { + return appPattern.test(appObj.name); + }); + } + // Don't use application filter if it empty + else if (appFilter === "") { + apps = undefined; + } + else { + var findedApp = _.find(this.cache.getApplications(), {'name': appFilter}); + if (findedApp) { + apps.push(findedApp); + } else { + // No applications finded + return []; + } + } + + // Find items belongs to selected applications + if (apps) { + var appids = _.flatten(_.map(apps, 'applicationids')); + items = _.filter(items, function (itemObj) { + return _.intersection(appids, itemObj.applications).length; + }); + } + + if (items) { + var itemPattern = utils.buildRegex(itemFilter); + items = _.filter(items, function (itemObj) { + return itemPattern.test(itemObj.name); + }); + } else { + // No items finded + return []; + } + } else { + items = _.filter(items, {'name': hostFilter}); + if (!items.length) { + // No items finded + return []; + } } - if (items) { - var itemPattern = utils.buildRegex(itemFilter); - items = _.filter(items, function (itemObj) { - return itemPattern.test(itemObj.name); - }); - } else { - // No items finded - return []; - } - } else { - items = _.filter(items, {'name': hostFilter}); - if (!items.length) { - // No items finded - return []; - } + // Set host as host name for each item + items = _.each(items, function (itemObj) { + itemObj.host = _.find(hosts, {'hostid': itemObj.hostid}).name; + }); + + return items; + }; + + /** + * Convert Zabbix API history.get response to Grafana format + * + * @return {Array} Array of timeseries in Grafana format + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * } + */ + this.convertHistory = function(history, addHostName, convertPointCallback) { + /** + * Response should be in the format: + * data: [ + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * }, ... + * ] + */ + + // Group history by itemid + var grouped_history = _.groupBy(history, 'itemid'); + + return _.map(grouped_history, function(hist, itemid) { + var item = self.cache.getItem(itemid); + var alias = item.name; + if (addHostName) { + var host = self.cache.getHost(item.hostid); + alias = host.name + ": " + alias; + } + return { + target: alias, + datapoints: _.map(hist, convertPointCallback) + }; + }); + }; + + this.handleHistory = function(history, addHostName) { + return this.convertHistory(history, addHostName, convertHistoryPoint); + }; + + this.handleTrends = function(history, addHostName, valueType) { + var convertPointCallback = _.partial(convertTrendPoint, valueType); + return this.convertHistory(history, addHostName, convertPointCallback); + }; + + function convertHistoryPoint(point) { + // Value must be a number for properly work + return [ + Number(point.value), + point.clock * 1000 + ]; } - // Set host as host name for each item - items = _.each(items, function (itemObj) { - itemObj.host = _.find(hosts, {'hostid': itemObj.hostid}).name; - }); + function convertTrendPoint(valueType, point) { + var value; + switch (valueType) { + case "min": + value = point.value_min; + break; + case "max": + value = point.value_max; + break; + case "avg": + value = point.value_avg; + break; + default: + value = point.value_avg; + } - return items; - }; + return [ + Number(value), + point.clock * 1000 + ]; + } + } - } - - return QueryBuilder; + return QueryBuilder; + }); }); \ No newline at end of file diff --git a/plugins/datasource-zabbix/zabbixAPI.js b/plugins/datasource-zabbix/zabbixAPI.js index 8f12599..00b41dd 100644 --- a/plugins/datasource-zabbix/zabbixAPI.js +++ b/plugins/datasource-zabbix/zabbixAPI.js @@ -118,12 +118,14 @@ function (angular, _) { /** * Perform history query from Zabbix API * - * @param {Array} items Array of Zabbix item objects - * @param {Number} start Time in seconds - * @param {Number} end Time in seconds - * @return {Array} Array of Zabbix history objects + * @param {Array} items Array of Zabbix item objects + * @param {Number} time_from Time in seconds + * @param {Number} time_till Time in seconds + * @return {Array} Array of Zabbix history objects */ - p.getHistory = function(items, start, end) { + p.getHistory = function(items, time_from, time_till) { + var self = this; + // Group items by value type var grouped_items = _.groupBy(items, 'value_type'); @@ -136,30 +138,30 @@ function (angular, _) { itemids: itemids, sortfield: 'clock', sortorder: 'ASC', - time_from: start + time_from: time_from }; // Relative queries (e.g. last hour) don't include an end time - if (end) { - params.time_till = end; + if (time_till) { + params.time_till = time_till; } - return this.request('history.get', params); - }, this)).then(function (results) { - return _.flatten(results); - }); + return self.request('history.get', params); + })).then(_.flatten); }; /** * Perform trends query from Zabbix API * Use trends api extension from ZBXNEXT-1193 patch. * - * @param {Array} items Array of Zabbix item objects - * @param {Number} start Time in seconds - * @param {Number} end Time in seconds - * @return {Array} Array of Zabbix trend objects + * @param {Array} items Array of Zabbix item objects + * @param {Number} time_from Time in seconds + * @param {Number} time_till Time in seconds + * @return {Array} Array of Zabbix trend objects */ - p.getTrends = function(items, start, end) { + p.getTrends = function(items, time_from, time_till) { + var self = this; + // Group items by value type var grouped_items = _.groupBy(items, 'value_type'); @@ -172,18 +174,16 @@ function (angular, _) { itemids: itemids, sortfield: 'clock', sortorder: 'ASC', - time_from: start + time_from: time_from }; // Relative queries (e.g. last hour) don't include an end time - if (end) { - params.time_till = end; + if (time_till) { + params.time_till = time_till; } - return this.request('trend.get', params); - }, this)).then(function (results) { - return _.flatten(results); - }); + return self.request('trend.get', params); + })).then(_.flatten); }; p.getITService = function(/* optional */ serviceids) { diff --git a/plugins/datasource-zabbix/zabbixCache.js b/plugins/datasource-zabbix/zabbixCache.js index e5d63f8..2a73773 100644 --- a/plugins/datasource-zabbix/zabbixCache.js +++ b/plugins/datasource-zabbix/zabbixCache.js @@ -70,6 +70,14 @@ function (angular, _, utils) { return this._items; }; + p.getHost = function(hostid) { + return _.find(this._hosts, {'hostid': hostid}); + }; + + p.getItem = function(itemid) { + return _.find(this._items, {'itemid': itemid}); + }; + /** * Convert host.get response to cache format * host.groups - array of group ids