From a8ae9f1fa79014dfff5d495f7c0a1fb83c53415b Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 8 Jul 2015 20:50:47 +0300 Subject: [PATCH 01/11] iss #43 - fixed code style errors. --- .gitignore | 5 +++ zabbix/datasource.js | 41 ++++++++++-------------- zabbix/queryCtrl.js | 36 +++++++-------------- zabbix/zabbixAPIWrapper.js | 64 +++++++++++++++----------------------- 4 files changed, 59 insertions(+), 87 deletions(-) diff --git a/.gitignore b/.gitignore index 1028d12..93706d6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,8 @@ .idea/ *.bat + +# Grafana linter config +.jshintrc +.jscs.json +.jsfmtrc \ No newline at end of file diff --git a/zabbix/datasource.js b/zabbix/datasource.js index 89df0ec..0a0bddb 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -1,3 +1,4 @@ +'use strict'; define([ 'angular', 'lodash', @@ -6,7 +7,7 @@ define([ './queryCtrl' ], function (angular, _, kbn) { - 'use strict'; + //'use strict'; var module = angular.module('grafana.services'); @@ -37,7 +38,6 @@ function (angular, _, kbn) { zabbix.init(this.url, this.username, this.password); } - /** * Calls for each panel in dashboard. * @@ -87,7 +87,7 @@ function (angular, _, kbn) { .then(function (items) { // Filter hosts by regex - if (target.host.visible_name == 'All') { + if (target.host.visible_name === 'All') { if (target.hostFilter && _.every(items, _.identity.hosts)) { var host_pattern = new RegExp(target.hostFilter); items = _.filter(items, function (item) { @@ -98,7 +98,7 @@ function (angular, _, kbn) { } } - if (itemnames == 'All') { + if (itemnames === 'All') { // Filter items by regex if (target.itemFilter) { @@ -154,7 +154,6 @@ function (angular, _, kbn) { }); }; - ZabbixAPIDatasource.prototype.handleTrendResponse = function(items, alias, scale, trends) { // Group items and trends by itemid @@ -183,7 +182,6 @@ function (angular, _, kbn) { }); }; - /** * Convert Zabbix API data to Grafana format * @@ -237,7 +235,6 @@ function (angular, _, kbn) { }); }; - /** * For templated query. * Find metrics from templated request. @@ -260,13 +257,13 @@ function (angular, _, kbn) { parts.push(part); } }); - var template = _.object(['group', 'host', 'app', 'item'], parts) + var template = _.object(['group', 'host', 'app', 'item'], parts); // Get items if (parts.length === 4) { return zabbix.itemFindQuery(template.group, template.host, template.app).then(function (result) { return _.map(result, function (item) { - var itemname = zabbix.expandItemName(item) + var itemname = zabbix.expandItemName(item); return { text: itemname, expandable: false @@ -315,12 +312,10 @@ function (angular, _, kbn) { } }; - ///////////////// // Annotations // ///////////////// - ZabbixAPIDatasource.prototype.annotationQuery = function(annotation, rangeUnparsed) { var from = Math.ceil(kbn.parseDate(rangeUnparsed.from).getTime() / 1000); var to = Math.ceil(kbn.parseDate(rangeUnparsed.to).getTime() / 1000); @@ -356,7 +351,7 @@ function (angular, _, kbn) { .then(function (result) { var events = []; _.each(result, function(e) { - var formatted_acknowledges = formatAcknowledges(e.acknowledges);; + var formatted_acknowledges = formatAcknowledges(e.acknowledges); events.push({ annotation: annotation, time: e.clock * 1000, @@ -365,18 +360,17 @@ function (angular, _, kbn) { }); }); return events; - }); + }); } else { return []; } - }); + }); }; return ZabbixAPIDatasource; }); }); - /** * Convert multiple mettrics to array * "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] @@ -387,10 +381,9 @@ function (angular, _, kbn) { function splitMetrics(metrics) { var remove_brackets_pattern = /^{|}$/g; var metric_split_pattern = /,(?!\s)/g; - return metrics.replace(remove_brackets_pattern, '').split(metric_split_pattern) + return metrics.replace(remove_brackets_pattern, '').split(metric_split_pattern); } - /** * Convert Date object to local time in format * YYYY-MM-DD HH:mm:ss @@ -407,7 +400,6 @@ function getShortTime(date) { return date.getFullYear() + '-' + MM + '-' + DD + ' ' + HH + ':' + mm + ':' + ss; } - /** * Format acknowledges. * @@ -416,21 +408,22 @@ function getShortTime(date) { */ function formatAcknowledges(acknowledges) { if (acknowledges.length) { - var formatted_acknowledges = '

Acknowledges:
'; + var formatted_acknowledges = '

Acknowledges:
TimeUserComments
' + + ''; _.each(_.map(acknowledges, function (ack) { var time = new Date(ack.clock * 1000); - return ''; + return ''; }), function (ack) { - formatted_acknowledges = formatted_acknowledges.concat(ack) + formatted_acknowledges = formatted_acknowledges.concat(ack); }); - formatted_acknowledges = formatted_acknowledges.concat('
TimeUserComments
' + getShortTime(time) + '' + ack.alias + ' (' + ack.name+ ' ' + ack.surname + ')' + '' + ack.message + '
' + getShortTime(time) + '' + ack.alias + + ' (' + ack.name + ' ' + ack.surname + ')' + '' + ack.message + '
') + formatted_acknowledges = formatted_acknowledges.concat(''); return formatted_acknowledges; } else { return ''; } } - /** * Downsample datapoints series * @@ -440,7 +433,7 @@ function formatAcknowledges(acknowledges) { * @return {array} [[, ], ...] */ function downsampleSeries(datapoints, time_to, ms_interval) { - var downsampledSeries = new Array(); + var downsampledSeries = []; var timeWindow = { from: time_to * 1000 - ms_interval, to: time_to * 1000 diff --git a/zabbix/queryCtrl.js b/zabbix/queryCtrl.js index 4f847c9..ceafa28 100644 --- a/zabbix/queryCtrl.js +++ b/zabbix/queryCtrl.js @@ -31,7 +31,6 @@ function (angular, _) { $scope.target.errors = validateTarget($scope.target); }; - /** * Take alias from item name by default */ @@ -39,8 +38,7 @@ function (angular, _) { if (!$scope.target.alias && $scope.target.item) { $scope.target.alias = $scope.target.item.name; } - }; - + } $scope.targetBlur = function() { setItemAlias(); @@ -51,12 +49,11 @@ function (angular, _) { } }; - /** * Call when host group selected */ $scope.selectHostGroup = function() { - $scope.updateHostList() + $scope.updateHostList(); $scope.updateAppList(); $scope.updateItemList(); @@ -67,7 +64,6 @@ function (angular, _) { } }; - /** * Call when host selected */ @@ -82,7 +78,6 @@ function (angular, _) { } }; - /** * Call when application selected */ @@ -96,7 +91,6 @@ function (angular, _) { } }; - /** * Call when item selected */ @@ -109,13 +103,11 @@ function (angular, _) { } }; - $scope.duplicate = function() { var clone = angular.copy($scope.target); $scope.panel.targets.push(clone); }; - $scope.moveMetricQuery = function(fromIndex, toIndex) { _.move($scope.panel.targets, fromIndex, toIndex); }; @@ -124,7 +116,6 @@ function (angular, _) { // SUGGESTION QUERIES ////////////////////////////// - /** * Update list of host groups */ @@ -137,7 +128,6 @@ function (angular, _) { }); }; - /** * Update list of hosts */ @@ -151,7 +141,6 @@ function (angular, _) { }); }; - /** * Update list of host applications */ @@ -162,19 +151,18 @@ function (angular, _) { var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; var hosts = $scope.target.host ? splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; zabbix.appFindQuery(hosts, groups).then(function (apps) { - var apps = _.map(_.uniq(_.map(apps, 'name')), function (appname) { + apps = _.map(_.uniq(_.map(apps, 'name')), function (appname) { return {name: appname}; }); $scope.metric.applicationList = $scope.metric.applicationList.concat(apps); }); }; - /** * Update list of items */ $scope.updateItemList = function() { - $scope.metric.itemList = [{name: 'All'}];; + $scope.metric.itemList = [{name: 'All'}]; addTemplatedVariables($scope.metric.itemList); var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; @@ -185,13 +173,12 @@ function (angular, _) { var uniq_items = _.map(_.uniq(items, function (item) { return zabbix.expandItemName(item); }), function (item) { - return {name: zabbix.expandItemName(item)} + return {name: zabbix.expandItemName(item)}; }); $scope.metric.itemList = $scope.metric.itemList.concat(uniq_items); }); }; - /** * Add templated variables to list of available metrics * @@ -202,10 +189,9 @@ function (angular, _) { metricList.push({ name: '$' + variable.name, templated: true - }) + }); }); - }; - + } ////////////////////////////// // VALIDATION @@ -213,7 +199,9 @@ function (angular, _) { function validateTarget(target) { var errs = {}; - + if (!target) { + errs = 'Not defined'; + } return errs; } @@ -221,7 +209,6 @@ function (angular, _) { }); - /** * Convert multiple mettrics to array * "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] @@ -230,7 +217,8 @@ function (angular, _) { * @return {Array} [metric1, metcic2,..., metricN] */ function splitMetrics(metrics) { + 'use strict'; var remove_brackets_pattern = /^{|}$/g; var metric_split_pattern = /,(?!\s)/g; - return metrics.replace(remove_brackets_pattern, '').split(metric_split_pattern) + return metrics.replace(remove_brackets_pattern, '').split(metric_split_pattern); } diff --git a/zabbix/zabbixAPIWrapper.js b/zabbix/zabbixAPIWrapper.js index eae7ea5..3ac7356 100644 --- a/zabbix/zabbixAPIWrapper.js +++ b/zabbix/zabbixAPIWrapper.js @@ -16,14 +16,12 @@ function (angular, _) { this.url = api_url; this.username = username; this.password = password; - } - + }; ////////////////// // Core methods // ////////////////// - /** * Request data from Zabbix API * @@ -56,9 +54,9 @@ function (angular, _) { else if (response.data.error) { // Handle auth errors - if (response.data.error.data == "Session terminated, re-login, please." || - response.data.error.data == "Not authorised." || - response.data.error.data == "Not authorized") { + if (response.data.error.data === "Session terminated, re-login, please." || + response.data.error.data === "Not authorised." || + response.data.error.data === "Not authorized") { return self.performZabbixAPILogin().then(function (response) { self.auth = response; return self.performZabbixAPIRequest(method, params); @@ -69,7 +67,6 @@ function (angular, _) { }); }; - /** * Get authentication token. * @@ -99,13 +96,10 @@ function (angular, _) { }); }; - - ///////////////////////// // API method wrappers // ///////////////////////// - /** * Perform history query from Zabbix API * @@ -141,7 +135,6 @@ function (angular, _) { }); }; - /** * Perform trends query from Zabbix API * Use trends api extension from ZBXNEXT-1193 patch. @@ -178,7 +171,6 @@ function (angular, _) { }); }; - /** * Get the list of host groups * @@ -197,7 +189,6 @@ function (angular, _) { return this.performZabbixAPIRequest('hostgroup.get', params); }; - /** * Get the list of hosts * @@ -220,7 +211,6 @@ function (angular, _) { return this.performZabbixAPIRequest('host.get', params); }; - /** * Get the list of applications * @@ -243,7 +233,6 @@ function (angular, _) { return this.performZabbixAPIRequest('application.get', params); }; - /** * Items request * @@ -287,7 +276,6 @@ function (angular, _) { return this.performZabbixAPIRequest('item.get', params); }; - /** * Get groups by names * @@ -298,7 +286,7 @@ function (angular, _) { var params = { output: ['name'] }; - if (group != '*') { + if (group !== '*') { params.filter = { name: group }; @@ -306,7 +294,6 @@ function (angular, _) { return this.performZabbixAPIRequest('hostgroup.get', params); }; - /** * Search group by name. * @@ -324,7 +311,6 @@ function (angular, _) { return this.performZabbixAPIRequest('hostgroup.get', params); }; - /** * Get hosts by names * @@ -335,7 +321,7 @@ function (angular, _) { var params = { output: ['host', 'name'] }; - if (hostnames != '*') { + if (hostnames !== '*') { params.filter = { name: hostnames }; @@ -343,7 +329,6 @@ function (angular, _) { return this.performZabbixAPIRequest('host.get', params); }; - /** * Get applications by names * @@ -353,16 +338,15 @@ function (angular, _) { this.getAppByName = function (application) { var params = { output: ['name'] - } - if (application != '*') { + }; + if (application !== '*') { params.filter = { name: application }; - }; + } return this.performZabbixAPIRequest('application.get', params); }; - /** * Get items belongs to passed groups, hosts and * applications @@ -376,7 +360,7 @@ function (angular, _) { var promises = []; // Get hostids from names - if (hosts && hosts != '*') { + if (hosts && hosts !== '*') { promises.push(this.getHostByName(hosts)); } // Get groupids from names @@ -391,18 +375,21 @@ function (angular, _) { var self = this; return $q.all(promises).then(function (results) { results = _.flatten(results); + var groupids; + var hostids; + var applicationids; if (groups) { - var groupids = _.map(_.filter(results, function (object) { + groupids = _.map(_.filter(results, function (object) { return object.groupid; }), 'groupid'); } - if (hosts && hosts != '*') { - var hostids = _.map(_.filter(results, function (object) { + if (hosts && hosts !== '*') { + hostids = _.map(_.filter(results, function (object) { return object.hostid; }), 'hostid'); } if (apps) { - var applicationids = _.map(_.filter(results, function (object) { + applicationids = _.map(_.filter(results, function (object) { return object.applicationid; }), 'applicationid'); } @@ -411,7 +398,6 @@ function (angular, _) { }); }; - /** * Find applications belongs to passed groups and hosts * @@ -423,7 +409,7 @@ function (angular, _) { var promises = []; // Get hostids from names - if (hosts && hosts != '*') { + if (hosts && hosts !== '*') { promises.push(this.getHostByName(hosts)); } // Get groupids from names @@ -434,13 +420,15 @@ function (angular, _) { var self = this; return $q.all(promises).then(function (results) { results = _.flatten(results); + var groupids; + var hostids; if (groups) { - var groupids = _.map(_.filter(results, function (object) { + groupids = _.map(_.filter(results, function (object) { return object.groupid; }), 'groupid'); } - if (hosts && hosts != '*') { - var hostids = _.map(_.filter(results, function (object) { + if (hosts && hosts !== '*') { + hostids = _.map(_.filter(results, function (object) { return object.hostid; }), 'hostid'); } @@ -449,7 +437,6 @@ function (angular, _) { }); }; - /** * Find hosts belongs to passed groups * @@ -468,7 +455,6 @@ function (angular, _) { }); }; - /** * Expand item parameters, for example: * CPU $2 time ($3) --> CPU system time (avg1) @@ -487,9 +473,9 @@ function (angular, _) { // replace item parameters for (var i = key_params.length; i >= 1; i--) { name = name.replace('$' + i, key_params[i - 1]); - }; + } return name; - } + }; }); }); From ea880c4cba5ab6534222000dfb6c82f88dcf6ae5 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 9 Jul 2015 23:02:18 +0300 Subject: [PATCH 02/11] Fixed #42 - multiple Zabbix datasources at one dashboard. Zabbix API implement as factory. --- zabbix/datasource.js | 44 +++++++++++++++++++---------------- zabbix/queryCtrl.js | 17 +++++++------- zabbix/zabbixAPIWrapper.js | 47 ++++++++++++++++++++------------------ 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index 0a0bddb..fd18637 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -11,7 +11,7 @@ function (angular, _, kbn) { var module = angular.module('grafana.services'); - module.factory('ZabbixAPIDatasource', function($q, backendSrv, templateSrv, zabbix) { + module.factory('ZabbixAPIDatasource', function($q, backendSrv, templateSrv, ZabbixAPI) { /** * Datasource initialization. Calls when you refresh page, add @@ -35,7 +35,7 @@ function (angular, _, kbn) { this.limitmetrics = datasource.meta.limitmetrics || 50; // Initialize Zabbix API - zabbix.init(this.url, this.username, this.password); + this.zabbixAPI = new ZabbixAPI(this.url, this.username, this.password); } /** @@ -83,7 +83,7 @@ function (angular, _, kbn) { // Find items by item names and perform queries var self = this; - return zabbix.itemFindQuery(groups, hosts, apps) + return this.zabbixAPI.itemFindQuery(groups, hosts, apps) .then(function (items) { // Filter hosts by regex @@ -98,13 +98,13 @@ function (angular, _, kbn) { } } - if (itemnames === 'All') { + if (itemnames == 'All') { // Filter items by regex if (target.itemFilter) { var item_pattern = new RegExp(target.itemFilter); return _.filter(items, function (item) { - return item_pattern.test(zabbix.expandItemName(item)); + return item_pattern.test(self.zabbixAPI.expandItemName(item)); }); } else { return items; @@ -113,7 +113,7 @@ function (angular, _, kbn) { // Filtering items return _.filter(items, function (item) { - return _.contains(itemnames, zabbix.expandItemName(item)); + return _.contains(itemnames, self.zabbixAPI.expandItemName(item)); }); } }).then(function (items) { @@ -129,11 +129,11 @@ function (angular, _, kbn) { var alias = items.length > 1 ? undefined : templateSrv.replace(target.alias); if ((from < useTrendsFrom) && self.trends) { - return zabbix.getTrends(items, from, to) - .then(_.partial(self.handleTrendResponse, items, alias, target.scale)); + return self.zabbixAPI.getTrends(items, from, to) + .then(_.bind(self.handleTrendResponse, self, items, alias, target.scale)); } else { - return zabbix.getHistory(items, from, to) - .then(_.partial(self.handleHistoryResponse, items, alias, target.scale)); + return self.zabbixAPI.getHistory(items, from, to) + .then(_.bind(self.handleHistoryResponse, self, items, alias, target.scale)); } } }); @@ -154,16 +154,18 @@ function (angular, _, kbn) { }); }; - ZabbixAPIDatasource.prototype.handleTrendResponse = function(items, alias, scale, trends) { + ZabbixAPIDatasource.prototype.handleTrendResponse = function (items, alias, scale, trends) { // Group items and trends by itemid var indexed_items = _.indexBy(items, 'itemid'); var grouped_history = _.groupBy(trends, 'itemid'); + var self = this; return $q.when(_.map(grouped_history, function (trends, itemid) { var item = indexed_items[itemid]; var series = { - target: (item.hosts ? item.hosts[0].name+': ' : '') + (alias ? alias : zabbix.expandItemName(item)), + target: (item.hosts ? item.hosts[0].name+': ' : '') + + (alias ? alias : self.zabbixAPI.expandItemName(item)), datapoints: _.map(trends, function (p) { // Value must be a number for properly work @@ -213,10 +215,12 @@ function (angular, _, kbn) { var indexed_items = _.indexBy(items, 'itemid'); var grouped_history = _.groupBy(history, 'itemid'); + var self = this; return $q.when(_.map(grouped_history, function (history, itemid) { var item = indexed_items[itemid]; var series = { - target: (item.hosts ? item.hosts[0].name+': ' : '') + (alias ? alias : zabbix.expandItemName(item)), + target: (item.hosts ? item.hosts[0].name+': ' : '') + + (alias ? alias : self.zabbixAPI.expandItemName(item)), datapoints: _.map(history, function (p) { // Value must be a number for properly work @@ -261,9 +265,9 @@ function (angular, _, kbn) { // Get items if (parts.length === 4) { - return zabbix.itemFindQuery(template.group, template.host, template.app).then(function (result) { + return this.zabbixAPI.itemFindQuery(template.group, template.host, template.app).then(function (result) { return _.map(result, function (item) { - var itemname = zabbix.expandItemName(item); + var itemname = this.zabbixAPI.expandItemName(item); return { text: itemname, expandable: false @@ -273,7 +277,7 @@ function (angular, _, kbn) { } // Get applications else if (parts.length === 3) { - return zabbix.appFindQuery(template.host, template.group).then(function (result) { + return this.zabbixAPI.appFindQuery(template.host, template.group).then(function (result) { return _.map(result, function (app) { return { text: app.name, @@ -284,7 +288,7 @@ function (angular, _, kbn) { } // Get hosts else if (parts.length === 2) { - return zabbix.hostFindQuery(template.group).then(function (result) { + return this.zabbixAPI.hostFindQuery(template.group).then(function (result) { return _.map(result, function (host) { return { text: host.name, @@ -295,7 +299,7 @@ function (angular, _, kbn) { } // Get groups else if (parts.length === 1) { - return zabbix.getGroupByName(template.group).then(function (result) { + return this.zabbixAPI.getGroupByName(template.group).then(function (result) { return _.map(result, function (hostgroup) { return { text: hostgroup.name, @@ -330,7 +334,7 @@ function (angular, _, kbn) { expandDescription: true }; - return this.performZabbixAPIRequest('trigger.get', params) + return this.zabbixAPI.performZabbixAPIRequest('trigger.get', params) .then(function (result) { if(result) { var objects = _.indexBy(result, 'triggerid'); @@ -347,7 +351,7 @@ function (angular, _, kbn) { params.value = 1; } - return self.performZabbixAPIRequest('event.get', params) + return self.zabbixAPI.performZabbixAPIRequest('event.get', params) .then(function (result) { var events = []; _.each(result, function(e) { diff --git a/zabbix/queryCtrl.js b/zabbix/queryCtrl.js index ceafa28..5a8770d 100644 --- a/zabbix/queryCtrl.js +++ b/zabbix/queryCtrl.js @@ -1,7 +1,6 @@ define([ 'angular', - 'lodash', - './zabbixAPIWrapper' + 'lodash' ], function (angular, _) { 'use strict'; @@ -9,7 +8,7 @@ function (angular, _) { var module = angular.module('grafana.controllers'); var targetLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - module.controller('ZabbixAPIQueryCtrl', function($scope, $sce, templateSrv, zabbix) { + module.controller('ZabbixAPIQueryCtrl', function($scope, $sce, templateSrv) { $scope.init = function() { $scope.targetLetters = targetLetters; @@ -123,7 +122,7 @@ function (angular, _) { $scope.metric.groupList = [{name: '*', visible_name: 'All'}]; addTemplatedVariables($scope.metric.groupList); - zabbix.performHostGroupSuggestQuery().then(function (groups) { + $scope.datasource.zabbixAPI.performHostGroupSuggestQuery().then(function (groups) { $scope.metric.groupList = $scope.metric.groupList.concat(groups); }); }; @@ -136,7 +135,7 @@ function (angular, _) { addTemplatedVariables($scope.metric.hostList); var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; - zabbix.hostFindQuery(groups).then(function (hosts) { + $scope.datasource.zabbixAPI.hostFindQuery(groups).then(function (hosts) { $scope.metric.hostList = $scope.metric.hostList.concat(hosts); }); }; @@ -150,7 +149,7 @@ function (angular, _) { var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; var hosts = $scope.target.host ? splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; - zabbix.appFindQuery(hosts, groups).then(function (apps) { + $scope.datasource.zabbixAPI.appFindQuery(hosts, groups).then(function (apps) { apps = _.map(_.uniq(_.map(apps, 'name')), function (appname) { return {name: appname}; }); @@ -168,12 +167,12 @@ function (angular, _) { var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; var hosts = $scope.target.host ? splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; var apps = $scope.target.application ? splitMetrics(templateSrv.replace($scope.target.application.name)) : undefined; - zabbix.itemFindQuery(groups, hosts, apps).then(function (items) { + $scope.datasource.zabbixAPI.itemFindQuery(groups, hosts, apps).then(function (items) { // Show only unique item names var uniq_items = _.map(_.uniq(items, function (item) { - return zabbix.expandItemName(item); + return $scope.datasource.zabbixAPI.expandItemName(item); }), function (item) { - return {name: zabbix.expandItemName(item)}; + return {name: $scope.datasource.zabbixAPI.expandItemName(item)}; }); $scope.metric.itemList = $scope.metric.itemList.concat(uniq_items); }); diff --git a/zabbix/zabbixAPIWrapper.js b/zabbix/zabbixAPIWrapper.js index 3ac7356..4dbb420 100644 --- a/zabbix/zabbixAPIWrapper.js +++ b/zabbix/zabbixAPIWrapper.js @@ -7,16 +7,16 @@ function (angular, _) { var module = angular.module('grafana.services'); - module.service('zabbix', function($q, backendSrv) { + module.factory('ZabbixAPI', function($q, backendSrv) { - /** - * Initialize API parameters. - */ - this.init = function(api_url, username, password) { + function ZabbixAPI(api_url, username, password) { + // Initialize API parameters. this.url = api_url; this.username = username; this.password = password; - }; + } + + var p = ZabbixAPI.prototype; ////////////////// // Core methods // @@ -29,7 +29,7 @@ function (angular, _) { * @param {object} params method params * @return {object} data.result field or [] */ - this.performZabbixAPIRequest = function(method, params) { + p.performZabbixAPIRequest = function(method, params) { var options = { method: 'POST', headers: { @@ -72,7 +72,7 @@ function (angular, _) { * * @return {string} auth token */ - this.performZabbixAPILogin = function() { + p.performZabbixAPILogin = function() { var options = { url : this.url, method : 'POST', @@ -108,7 +108,7 @@ function (angular, _) { * @param {Number} end Time in seconds * @return {Array} Array of Zabbix history objects */ - this.getHistory = function(items, start, end) { + p.getHistory = function(items, start, end) { // Group items by value type var grouped_items = _.groupBy(items, 'value_type'); @@ -144,7 +144,7 @@ function (angular, _) { * @param {Number} end Time in seconds * @return {Array} Array of Zabbix trend objects */ - this.getTrends = function(items, start, end) { + p.getTrends = function(items, start, end) { // Group items by value type var grouped_items = _.groupBy(items, 'value_type'); @@ -176,7 +176,7 @@ function (angular, _) { * * @return {array} array of Zabbix hostgroup objects */ - this.performHostGroupSuggestQuery = function() { + p.performHostGroupSuggestQuery = function() { var params = { output: ['name'], sortfield: 'name', @@ -195,7 +195,7 @@ function (angular, _) { * @param {array} groupids * @return {array} array of Zabbix host objects */ - this.performHostSuggestQuery = function(groupids) { + p.performHostSuggestQuery = function(groupids) { var params = { output: ['name', 'host'], sortfield: 'name', @@ -218,7 +218,7 @@ function (angular, _) { * @param {array} groupids * @return {array} array of Zabbix application objects */ - this.performAppSuggestQuery = function(hostids, /* optional */ groupids) { + p.performAppSuggestQuery = function(hostids, /* optional */ groupids) { var params = { output: ['name'], sortfield: 'name' @@ -241,7 +241,7 @@ function (angular, _) { * @param {string or Array} groupids /////////////////////////// * @return {string or Array} Array of Zabbix API item objects */ - this.performItemSuggestQuery = function(hostids, applicationids, /* optional */ groupids) { + p.performItemSuggestQuery = function(hostids, applicationids, /* optional */ groupids) { var params = { output: ['name', 'key_', 'value_type', 'delay'], sortfield: 'name', @@ -282,7 +282,7 @@ function (angular, _) { * @param {string or array} group group names * @return {array} array of Zabbix API hostgroup objects */ - this.getGroupByName = function (group) { + p.getGroupByName = function (group) { var params = { output: ['name'] }; @@ -300,7 +300,7 @@ function (angular, _) { * @param {string} group group name * @return {array} groups */ - this.searchGroup = function (group) { + p.searchGroup = function (group) { var params = { output: ['name'], search: { @@ -317,7 +317,7 @@ function (angular, _) { * @param {string or array} hostnames hosts names * @return {array} array of Zabbix API host objects */ - this.getHostByName = function (hostnames) { + p.getHostByName = function (hostnames) { var params = { output: ['host', 'name'] }; @@ -335,7 +335,7 @@ function (angular, _) { * @param {string or array} application applications names * @return {array} array of Zabbix API application objects */ - this.getAppByName = function (application) { + p.getAppByName = function (application) { var params = { output: ['name'] }; @@ -356,7 +356,7 @@ function (angular, _) { * @param {string or array} apps * @return {array} array of Zabbix API item objects */ - this.itemFindQuery = function(groups, hosts, apps) { + p.itemFindQuery = function(groups, hosts, apps) { var promises = []; // Get hostids from names @@ -405,7 +405,7 @@ function (angular, _) { * @param {string or array} groups * @return {array} array of Zabbix API application objects */ - this.appFindQuery = function(hosts, groups) { + p.appFindQuery = function(hosts, groups) { var promises = []; // Get hostids from names @@ -443,7 +443,7 @@ function (angular, _) { * @param {string or array} groups * @return {array} array of Zabbix API host objects */ - this.hostFindQuery = function(groups) { + p.hostFindQuery = function(groups) { var self = this; return this.getGroupByName(groups).then(function (results) { results = _.flatten(results); @@ -462,7 +462,7 @@ function (angular, _) { * @param item: zabbix api item object * @return: expanded item name (string) */ - this.expandItemName = function(item) { + p.expandItemName = function(item) { var name = item.name; var key = item.key_; @@ -477,5 +477,8 @@ function (angular, _) { return name; }; + return ZabbixAPI; + }); + }); From ed30596abd53599d5f81091c4acff42b30fb0ab3 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Fri, 10 Jul 2015 14:16:08 +0300 Subject: [PATCH 03/11] iss #43 - Some refactoring fixes. --- zabbix/datasource.js | 23 ++++++++++++++--------- zabbix/zabbixAPIWrapper.js | 14 +++++++------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index fd18637..db23d88 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -239,8 +239,11 @@ function (angular, _, kbn) { }); }; + //////////////// + // Templating // + //////////////// + /** - * For templated query. * Find metrics from templated request. * * @param {string} query Query from Templating @@ -264,16 +267,18 @@ function (angular, _, kbn) { var template = _.object(['group', 'host', 'app', 'item'], parts); // Get items + var self = this; if (parts.length === 4) { - return this.zabbixAPI.itemFindQuery(template.group, template.host, template.app).then(function (result) { - return _.map(result, function (item) { - var itemname = this.zabbixAPI.expandItemName(item); - return { - text: itemname, - expandable: false - }; + return this.zabbixAPI.itemFindQuery(template.group, template.host, template.app) + .then(function (result) { + return _.map(result, function (item) { + var itemname = self.zabbixAPI.expandItemName(item); + return { + text: itemname, + expandable: false + }; + }); }); - }); } // Get applications else if (parts.length === 3) { diff --git a/zabbix/zabbixAPIWrapper.js b/zabbix/zabbixAPIWrapper.js index 4dbb420..b067195 100644 --- a/zabbix/zabbixAPIWrapper.js +++ b/zabbix/zabbixAPIWrapper.js @@ -286,7 +286,7 @@ function (angular, _) { var params = { output: ['name'] }; - if (group !== '*') { + if (group[0] !== '*') { params.filter = { name: group }; @@ -321,7 +321,7 @@ function (angular, _) { var params = { output: ['host', 'name'] }; - if (hostnames !== '*') { + if (hostnames[0] !== '*') { params.filter = { name: hostnames }; @@ -339,7 +339,7 @@ function (angular, _) { var params = { output: ['name'] }; - if (application !== '*') { + if (application[0] !== '*') { params.filter = { name: application }; @@ -360,7 +360,7 @@ function (angular, _) { var promises = []; // Get hostids from names - if (hosts && hosts !== '*') { + if (hosts && hosts[0] !== '*') { promises.push(this.getHostByName(hosts)); } // Get groupids from names @@ -383,7 +383,7 @@ function (angular, _) { return object.groupid; }), 'groupid'); } - if (hosts && hosts !== '*') { + if (hosts && hosts[0] !== '*') { hostids = _.map(_.filter(results, function (object) { return object.hostid; }), 'hostid'); @@ -409,7 +409,7 @@ function (angular, _) { var promises = []; // Get hostids from names - if (hosts && hosts !== '*') { + if (hosts && hosts[0] !== '*') { promises.push(this.getHostByName(hosts)); } // Get groupids from names @@ -427,7 +427,7 @@ function (angular, _) { return object.groupid; }), 'groupid'); } - if (hosts && hosts !== '*') { + if (hosts && hosts[0] !== '*') { hostids = _.map(_.filter(results, function (object) { return object.hostid; }), 'hostid'); From 769a59446ec26cc33c351922d25eb3352327f3da Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Fri, 10 Jul 2015 14:18:45 +0300 Subject: [PATCH 04/11] iss #46 - Handle case when All hosts single item selected (use alias for items). --- zabbix/datasource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index db23d88..17a83a5 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -126,7 +126,7 @@ function (angular, _, kbn) { items = _.flatten(items); // Use alias only for single metric, otherwise use item names - var alias = items.length > 1 ? undefined : templateSrv.replace(target.alias); + var alias = target.item.name === 'All' || itemnames.length > 1 ? undefined : templateSrv.replace(target.alias); if ((from < useTrendsFrom) && self.trends) { return self.zabbixAPI.getTrends(items, from, to) From 41e853392522bab9e84c739767a9d55ab61a1f86 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Fri, 10 Jul 2015 19:51:17 +0300 Subject: [PATCH 05/11] iss #43 - Handle functions moved to helperFunctions.js (zabbixHelperSrv service). Fixed #43 - build passed without errors. --- zabbix/datasource.js | 113 ++++---------------------------------- zabbix/helperFunctions.js | 107 ++++++++++++++++++++++++++++++++++++ zabbix/queryCtrl.js | 31 +++-------- 3 files changed, 126 insertions(+), 125 deletions(-) create mode 100644 zabbix/helperFunctions.js diff --git a/zabbix/datasource.js b/zabbix/datasource.js index 17a83a5..94eec2b 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -4,6 +4,7 @@ define([ 'lodash', 'kbn', './zabbixAPIWrapper', + './helperFunctions', './queryCtrl' ], function (angular, _, kbn) { @@ -11,7 +12,7 @@ function (angular, _, kbn) { var module = angular.module('grafana.services'); - module.factory('ZabbixAPIDatasource', function($q, backendSrv, templateSrv, ZabbixAPI) { + module.factory('ZabbixAPIDatasource', function($q, backendSrv, templateSrv, ZabbixAPI, zabbixHelperSrv) { /** * Datasource initialization. Calls when you refresh page, add @@ -71,15 +72,15 @@ function (angular, _, kbn) { // Extract zabbix groups, hosts and apps from string: // "{host1,host2,...,hostN}" --> [host1, host2, ..., hostN] - var groups = splitMetrics(groupname); - var hosts = splitMetrics(hostname); - var apps = splitMetrics(appname); + var groups = zabbixHelperSrv.splitMetrics(groupname); + var hosts = zabbixHelperSrv.splitMetrics(hostname); + var apps = zabbixHelperSrv.splitMetrics(appname); // Remove hostnames from item names and then // extract item names // "hostname: itemname" --> "itemname" var delete_hostname_pattern = /(?:\[[\w\.]+\]\:\s)/g; - var itemnames = splitMetrics(itemname.replace(delete_hostname_pattern, '')); + var itemnames = zabbixHelperSrv.splitMetrics(itemname.replace(delete_hostname_pattern, '')); // Find items by item names and perform queries var self = this; @@ -98,7 +99,7 @@ function (angular, _, kbn) { } } - if (itemnames == 'All') { + if (itemnames[0] === 'All') { // Filter items by regex if (target.itemFilter) { @@ -146,7 +147,7 @@ function (angular, _, kbn) { // Series downsampling if (timeseries.datapoints.length > options.maxDataPoints) { var ms_interval = Math.floor((to - from) / options.maxDataPoints) * 1000; - timeseries.datapoints = downsampleSeries(timeseries.datapoints, to, ms_interval); + timeseries.datapoints = zabbixHelperSrv.downsampleSeries(timeseries.datapoints, to, ms_interval); } return timeseries; }); @@ -259,7 +260,7 @@ function (angular, _, kbn) { if (part[0] === '{') { // Convert multiple mettrics to array // "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] - parts.push(splitMetrics(part)); + parts.push(zabbixHelperSrv.splitMetrics(part)); } else { parts.push(part); } @@ -360,7 +361,7 @@ function (angular, _, kbn) { .then(function (result) { var events = []; _.each(result, function(e) { - var formatted_acknowledges = formatAcknowledges(e.acknowledges); + var formatted_acknowledges = zabbixHelperSrv.formatAcknowledges(e.acknowledges); events.push({ annotation: annotation, time: e.clock * 1000, @@ -379,97 +380,3 @@ function (angular, _, kbn) { return ZabbixAPIDatasource; }); }); - -/** - * Convert multiple mettrics to array - * "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] - * - * @param {string} metrics "{metric1,metcic2,...,metricN}" - * @return {Array} [metric1, metcic2,..., metricN] - */ -function splitMetrics(metrics) { - var remove_brackets_pattern = /^{|}$/g; - var metric_split_pattern = /,(?!\s)/g; - return metrics.replace(remove_brackets_pattern, '').split(metric_split_pattern); -} - -/** - * Convert Date object to local time in format - * YYYY-MM-DD HH:mm:ss - * - * @param {Date} date Date object - * @return {string} formatted local time YYYY-MM-DD HH:mm:ss - */ -function getShortTime(date) { - var MM = date.getMonth() < 10 ? '0' + date.getMonth() : date.getMonth(); - var DD = date.getDate() < 10 ? '0' + date.getDate() : date.getDate(); - var HH = date.getHours() < 10 ? '0' + date.getHours() : date.getHours(); - var mm = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes(); - var ss = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds(); - return date.getFullYear() + '-' + MM + '-' + DD + ' ' + HH + ':' + mm + ':' + ss; -} - -/** - * Format acknowledges. - * - * @param {array} acknowledges array of Zabbix acknowledge objects - * @return {string} HTML-formatted table - */ -function formatAcknowledges(acknowledges) { - if (acknowledges.length) { - var formatted_acknowledges = '

Acknowledges:
' - + ''; - _.each(_.map(acknowledges, function (ack) { - var time = new Date(ack.clock * 1000); - return ''; - }), function (ack) { - formatted_acknowledges = formatted_acknowledges.concat(ack); - }); - formatted_acknowledges = formatted_acknowledges.concat('
TimeUserComments
' + getShortTime(time) + '' + ack.alias - + ' (' + ack.name + ' ' + ack.surname + ')' + '' + ack.message + '
'); - return formatted_acknowledges; - } else { - return ''; - } -} - -/** - * Downsample datapoints series - * - * @param {array} datapoints [[, ], ...] - * @param {integer} time_to Panel time to - * @param {integer} ms_interval Interval in milliseconds for grouping datapoints - * @return {array} [[, ], ...] - */ -function downsampleSeries(datapoints, time_to, ms_interval) { - 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; - 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++; - } - else { - value_avg = points_num ? points_sum / points_num : 0; - downsampledSeries.push([value_avg, timeWindow.to]); - - // Shift time window - timeWindow.to = timeWindow.from; - timeWindow.from -= ms_interval; - - points_sum = 0; - points_num = 0; - - // Process point again - i++; - } - } - return downsampledSeries.reverse(); -} \ No newline at end of file diff --git a/zabbix/helperFunctions.js b/zabbix/helperFunctions.js new file mode 100644 index 0000000..f316b9f --- /dev/null +++ b/zabbix/helperFunctions.js @@ -0,0 +1,107 @@ +define([ + 'angular', + 'lodash' +], +function (angular, _) { + 'use strict'; + + var module = angular.module('grafana.services'); + + module.service('zabbixHelperSrv', function() { + var self = this; + + /** + * Convert multiple mettrics to array + * "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] + * + * @param {string} metrics "{metric1,metcic2,...,metricN}" + * @return {Array} [metric1, metcic2,..., metricN] + */ + this.splitMetrics = function(metrics) { + var remove_brackets_pattern = /^{|}$/g; + var metric_split_pattern = /,(?!\s)/g; + return metrics.replace(remove_brackets_pattern, '').split(metric_split_pattern); + }; + + /** + * Convert Date object to local time in format + * YYYY-MM-DD HH:mm:ss + * + * @param {Date} date Date object + * @return {string} formatted local time YYYY-MM-DD HH:mm:ss + */ + this.getShortTime = function(date) { + var MM = date.getMonth() < 10 ? '0' + date.getMonth() : date.getMonth(); + var DD = date.getDate() < 10 ? '0' + date.getDate() : date.getDate(); + var HH = date.getHours() < 10 ? '0' + date.getHours() : date.getHours(); + var mm = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes(); + var ss = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds(); + return date.getFullYear() + '-' + MM + '-' + DD + ' ' + HH + ':' + mm + ':' + ss; + }; + + /** + * Format acknowledges. + * + * @param {array} acknowledges array of Zabbix acknowledge objects + * @return {string} HTML-formatted table + */ + this.formatAcknowledges = function(acknowledges) { + if (acknowledges.length) { + var formatted_acknowledges = '

Acknowledges:
' + + ''; + _.each(_.map(acknowledges, function (ack) { + var time = new Date(ack.clock * 1000); + return ''; + }), function (ack) { + formatted_acknowledges = formatted_acknowledges.concat(ack); + }); + formatted_acknowledges = formatted_acknowledges.concat('
TimeUserComments
' + self.getShortTime(time) + '' + ack.alias + + ' (' + ack.name + ' ' + ack.surname + ')' + '' + ack.message + '
'); + return formatted_acknowledges; + } else { + return ''; + } + }; + + /** + * Downsample datapoints series + * + * @param {array} datapoints [[, ], ...] + * @param {integer} time_to Panel time to + * @param {integer} ms_interval Interval in milliseconds for grouping datapoints + * @return {array} [[, ], ...] + */ + this.downsampleSeries = function(datapoints, time_to, ms_interval) { + 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; + 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++; + } + else { + value_avg = points_num ? points_sum / points_num : 0; + downsampledSeries.push([value_avg, timeWindow.to]); + + // Shift time window + timeWindow.to = timeWindow.from; + timeWindow.from -= ms_interval; + + points_sum = 0; + points_num = 0; + + // Process point again + i++; + } + } + return downsampledSeries.reverse(); + }; + }); +}); \ No newline at end of file diff --git a/zabbix/queryCtrl.js b/zabbix/queryCtrl.js index 5a8770d..76bf47e 100644 --- a/zabbix/queryCtrl.js +++ b/zabbix/queryCtrl.js @@ -1,6 +1,7 @@ define([ 'angular', - 'lodash' + 'lodash', + './helperFunctions' ], function (angular, _) { 'use strict'; @@ -8,7 +9,7 @@ function (angular, _) { var module = angular.module('grafana.controllers'); var targetLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - module.controller('ZabbixAPIQueryCtrl', function($scope, $sce, templateSrv) { + module.controller('ZabbixAPIQueryCtrl', function($scope, $sce, templateSrv, zabbixHelperSrv) { $scope.init = function() { $scope.targetLetters = targetLetters; @@ -134,7 +135,7 @@ function (angular, _) { $scope.metric.hostList = [{name: '*', visible_name: 'All'}]; addTemplatedVariables($scope.metric.hostList); - var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; + var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; $scope.datasource.zabbixAPI.hostFindQuery(groups).then(function (hosts) { $scope.metric.hostList = $scope.metric.hostList.concat(hosts); }); @@ -147,8 +148,8 @@ function (angular, _) { $scope.metric.applicationList = [{name: '*', visible_name: 'All'}]; addTemplatedVariables($scope.metric.applicationList); - var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; - var hosts = $scope.target.host ? splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; + var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; + var hosts = $scope.target.host ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; $scope.datasource.zabbixAPI.appFindQuery(hosts, groups).then(function (apps) { apps = _.map(_.uniq(_.map(apps, 'name')), function (appname) { return {name: appname}; @@ -164,9 +165,9 @@ function (angular, _) { $scope.metric.itemList = [{name: 'All'}]; addTemplatedVariables($scope.metric.itemList); - var groups = $scope.target.group ? splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; - var hosts = $scope.target.host ? splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; - var apps = $scope.target.application ? splitMetrics(templateSrv.replace($scope.target.application.name)) : undefined; + var groups = $scope.target.group ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.group.name)) : undefined; + var hosts = $scope.target.host ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.host.name)) : undefined; + var apps = $scope.target.application ? zabbixHelperSrv.splitMetrics(templateSrv.replace($scope.target.application.name)) : undefined; $scope.datasource.zabbixAPI.itemFindQuery(groups, hosts, apps).then(function (items) { // Show only unique item names var uniq_items = _.map(_.uniq(items, function (item) { @@ -207,17 +208,3 @@ function (angular, _) { }); }); - -/** - * Convert multiple mettrics to array - * "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] - * - * @param {string} metrics "{metric1,metcic2,...,metricN}" - * @return {Array} [metric1, metcic2,..., metricN] - */ -function splitMetrics(metrics) { - 'use strict'; - var remove_brackets_pattern = /^{|}$/g; - var metric_split_pattern = /,(?!\s)/g; - return metrics.replace(remove_brackets_pattern, '').split(metric_split_pattern); -} From 11cf488d71e1da341b2f4c29c043bc5388ba0f70 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sat, 11 Jul 2015 10:37:48 +0300 Subject: [PATCH 06/11] limitmetrics parameter increased to 100 by default. --- zabbix/datasource.js | 2 +- zabbix/plugin.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index 94eec2b..c9f7c4b 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -33,7 +33,7 @@ function (angular, _, kbn) { this.trendsFrom = datasource.meta.trendsFrom || '7d'; // Limit metrics per panel for templated request - this.limitmetrics = datasource.meta.limitmetrics || 50; + this.limitmetrics = datasource.meta.limitmetrics || 100; // Initialize Zabbix API this.zabbixAPI = new ZabbixAPI(this.url, this.username, this.password); diff --git a/zabbix/plugin.json b/zabbix/plugin.json index 0ff34a5..c95ec01 100644 --- a/zabbix/plugin.json +++ b/zabbix/plugin.json @@ -19,7 +19,7 @@ "trends": false, "trendsFrom": "7d", - "limitmetrics": 50, + "limitmetrics": 100, "metrics": true, "annotations": true From 082d56e1a68d105b4d2eff1aa91d8c60765d69d9 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sat, 11 Jul 2015 10:55:17 +0300 Subject: [PATCH 07/11] History and trends response handling moved to helperFunctions.js. --- zabbix/datasource.js | 89 +---------------------------------- zabbix/helperFunctions.js | 99 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 88 deletions(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index c9f7c4b..571a0f9 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -131,10 +131,10 @@ function (angular, _, kbn) { if ((from < useTrendsFrom) && self.trends) { return self.zabbixAPI.getTrends(items, from, to) - .then(_.bind(self.handleTrendResponse, self, items, alias, target.scale)); + .then(_.bind(zabbixHelperSrv.handleTrendResponse, self, items, alias, target.scale)); } else { return self.zabbixAPI.getHistory(items, from, to) - .then(_.bind(self.handleHistoryResponse, self, items, alias, target.scale)); + .then(_.bind(zabbixHelperSrv.handleHistoryResponse, self, items, alias, target.scale)); } } }); @@ -155,91 +155,6 @@ function (angular, _, kbn) { }); }; - ZabbixAPIDatasource.prototype.handleTrendResponse = function (items, alias, scale, trends) { - - // Group items and trends by itemid - var indexed_items = _.indexBy(items, 'itemid'); - var grouped_history = _.groupBy(trends, 'itemid'); - - var self = this; - return $q.when(_.map(grouped_history, function (trends, itemid) { - var item = indexed_items[itemid]; - var series = { - target: (item.hosts ? item.hosts[0].name+': ' : '') - + (alias ? alias : self.zabbixAPI.expandItemName(item)), - datapoints: _.map(trends, function (p) { - - // Value must be a number for properly work - var value = Number(p.value_avg); - - // Apply scale - if (scale) { - value *= scale; - } - return [value, p.clock * 1000]; - }) - }; - return series; - })).then(function (result) { - return _.sortBy(result, 'target'); - }); - }; - - /** - * Convert Zabbix API data to Grafana format - * - * @param {Array} items Array of Zabbix Items - * @param {Array} history Array of Zabbix History - * - * @return {Array} Array of timeseries in Grafana format - * { - * target: "Metric name", - * datapoints: [[, ], ...] - * } - */ - ZabbixAPIDatasource.prototype.handleHistoryResponse = function(items, alias, scale, history) { - /** - * Response should be in the format: - * data: [ - * { - * target: "Metric name", - * datapoints: [[, ], ...] - * }, - * { - * target: "Metric name", - * datapoints: [[, ], ...] - * }, - * ] - */ - - // Group items and history by itemid - var indexed_items = _.indexBy(items, 'itemid'); - var grouped_history = _.groupBy(history, 'itemid'); - - var self = this; - return $q.when(_.map(grouped_history, function (history, itemid) { - var item = indexed_items[itemid]; - var series = { - target: (item.hosts ? item.hosts[0].name+': ' : '') - + (alias ? alias : self.zabbixAPI.expandItemName(item)), - datapoints: _.map(history, function (p) { - - // Value must be a number for properly work - var value = Number(p.value); - - // Apply scale - if (scale) { - value *= scale; - } - return [value, p.clock * 1000]; - }) - }; - return series; - })).then(function (result) { - return _.sortBy(result, 'target'); - }); - }; - //////////////// // Templating // //////////////// diff --git a/zabbix/helperFunctions.js b/zabbix/helperFunctions.js index f316b9f..1b91958 100644 --- a/zabbix/helperFunctions.js +++ b/zabbix/helperFunctions.js @@ -7,9 +7,106 @@ function (angular, _) { var module = angular.module('grafana.services'); - module.service('zabbixHelperSrv', function() { + module.service('zabbixHelperSrv', function($q) { var self = this; + /** + * Convert Zabbix API history.get response to Grafana format + * + * @param {Array} items Array of Zabbix Items + * @param {Array} history Array of Zabbix History + * + * @return {Array} Array of timeseries in Grafana format + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * } + */ + this.handleHistoryResponse = function(items, alias, scale, history) { + /** + * Response should be in the format: + * data: [ + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * }, + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * }, + * ] + */ + + // Group items and history by itemid + var indexed_items = _.indexBy(items, 'itemid'); + var grouped_history = _.groupBy(history, 'itemid'); + + var self = this; + return $q.when(_.map(grouped_history, function (history, itemid) { + var item = indexed_items[itemid]; + var series = { + target: (item.hosts ? item.hosts[0].name+': ' : '') + + (alias ? alias : self.zabbixAPI.expandItemName(item)), + datapoints: _.map(history, function (p) { + + // Value must be a number for properly work + var value = Number(p.value); + + // Apply scale + if (scale) { + value *= scale; + } + return [value, p.clock * 1000]; + }) + }; + return series; + })).then(function (result) { + return _.sortBy(result, 'target'); + }); + }; + + /** + * Convert Zabbix API trends.get response to Grafana format + * + * @param {Array} items Array of Zabbix Items + * @param {Array} trends Array of Zabbix Trends + * + * @return {Array} Array of timeseries in Grafana format + * { + * target: "Metric name", + * datapoints: [[, ], ...] + * } + */ + this.handleTrendResponse = function (items, alias, scale, trends) { + + // Group items and trends by itemid + var indexed_items = _.indexBy(items, 'itemid'); + var grouped_trends = _.groupBy(trends, 'itemid'); + + var self = this; + return $q.when(_.map(grouped_trends, function (trends, itemid) { + var item = indexed_items[itemid]; + var series = { + target: (item.hosts ? item.hosts[0].name+': ' : '') + + (alias ? alias : self.zabbixAPI.expandItemName(item)), + datapoints: _.map(trends, function (p) { + + // Value must be a number for properly work + var value = Number(p.value_avg); + + // Apply scale + if (scale) { + value *= scale; + } + return [value, p.clock * 1000]; + }) + }; + return series; + })).then(function (result) { + return _.sortBy(result, 'target'); + }); + }; + /** * Convert multiple mettrics to array * "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] From c3def217deaea4d59ace608a398908dbbdee7148 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sat, 11 Jul 2015 11:09:34 +0300 Subject: [PATCH 08/11] expandItemName function moved to helperFunctions.js. --- zabbix/datasource.js | 11 +++++------ zabbix/helperFunctions.js | 26 ++++++++++++++++++++++++-- zabbix/queryCtrl.js | 4 ++-- zabbix/zabbixAPIWrapper.js | 22 ---------------------- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index 571a0f9..ccdebea 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -105,7 +105,7 @@ function (angular, _, kbn) { if (target.itemFilter) { var item_pattern = new RegExp(target.itemFilter); return _.filter(items, function (item) { - return item_pattern.test(self.zabbixAPI.expandItemName(item)); + return item_pattern.test(zabbixHelperSrv.expandItemName(item)); }); } else { return items; @@ -114,7 +114,7 @@ function (angular, _, kbn) { // Filtering items return _.filter(items, function (item) { - return _.contains(itemnames, self.zabbixAPI.expandItemName(item)); + return _.contains(itemnames, zabbixHelperSrv.expandItemName(item)); }); } }).then(function (items) { @@ -131,10 +131,10 @@ function (angular, _, kbn) { if ((from < useTrendsFrom) && self.trends) { return self.zabbixAPI.getTrends(items, from, to) - .then(_.bind(zabbixHelperSrv.handleTrendResponse, self, items, alias, target.scale)); + .then(_.bind(zabbixHelperSrv.handleTrendResponse, zabbixHelperSrv, items, alias, target.scale)); } else { return self.zabbixAPI.getHistory(items, from, to) - .then(_.bind(zabbixHelperSrv.handleHistoryResponse, self, items, alias, target.scale)); + .then(_.bind(zabbixHelperSrv.handleHistoryResponse, zabbixHelperSrv, items, alias, target.scale)); } } }); @@ -183,12 +183,11 @@ function (angular, _, kbn) { var template = _.object(['group', 'host', 'app', 'item'], parts); // Get items - var self = this; if (parts.length === 4) { return this.zabbixAPI.itemFindQuery(template.group, template.host, template.app) .then(function (result) { return _.map(result, function (item) { - var itemname = self.zabbixAPI.expandItemName(item); + var itemname = zabbixHelperSrv.expandItemName(item); return { text: itemname, expandable: false diff --git a/zabbix/helperFunctions.js b/zabbix/helperFunctions.js index 1b91958..34bb84e 100644 --- a/zabbix/helperFunctions.js +++ b/zabbix/helperFunctions.js @@ -46,7 +46,7 @@ function (angular, _) { var item = indexed_items[itemid]; var series = { target: (item.hosts ? item.hosts[0].name+': ' : '') - + (alias ? alias : self.zabbixAPI.expandItemName(item)), + + (alias ? alias : self.expandItemName(item)), datapoints: _.map(history, function (p) { // Value must be a number for properly work @@ -88,7 +88,7 @@ function (angular, _) { var item = indexed_items[itemid]; var series = { target: (item.hosts ? item.hosts[0].name+': ' : '') - + (alias ? alias : self.zabbixAPI.expandItemName(item)), + + (alias ? alias : self.expandItemName(item)), datapoints: _.map(trends, function (p) { // Value must be a number for properly work @@ -107,6 +107,28 @@ function (angular, _) { }); }; + /** + * Expand item parameters, for example: + * CPU $2 time ($3) --> CPU system time (avg1) + * + * @param item: zabbix api item object + * @return: expanded item name (string) + */ + this.expandItemName = function(item) { + var name = item.name; + var key = item.key_; + + // extract params from key: + // "system.cpu.util[,system,avg1]" --> ["", "system", "avg1"] + var key_params = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')).split(','); + + // replace item parameters + for (var i = key_params.length; i >= 1; i--) { + name = name.replace('$' + i, key_params[i - 1]); + } + return name; + }; + /** * Convert multiple mettrics to array * "{metric1,metcic2,...,metricN}" --> [metric1, metcic2,..., metricN] diff --git a/zabbix/queryCtrl.js b/zabbix/queryCtrl.js index 76bf47e..053d4f4 100644 --- a/zabbix/queryCtrl.js +++ b/zabbix/queryCtrl.js @@ -171,9 +171,9 @@ function (angular, _) { $scope.datasource.zabbixAPI.itemFindQuery(groups, hosts, apps).then(function (items) { // Show only unique item names var uniq_items = _.map(_.uniq(items, function (item) { - return $scope.datasource.zabbixAPI.expandItemName(item); + return zabbixHelperSrv.expandItemName(item); }), function (item) { - return {name: $scope.datasource.zabbixAPI.expandItemName(item)}; + return {name: zabbixHelperSrv.expandItemName(item)}; }); $scope.metric.itemList = $scope.metric.itemList.concat(uniq_items); }); diff --git a/zabbix/zabbixAPIWrapper.js b/zabbix/zabbixAPIWrapper.js index b067195..626764a 100644 --- a/zabbix/zabbixAPIWrapper.js +++ b/zabbix/zabbixAPIWrapper.js @@ -455,28 +455,6 @@ function (angular, _) { }); }; - /** - * Expand item parameters, for example: - * CPU $2 time ($3) --> CPU system time (avg1) - * - * @param item: zabbix api item object - * @return: expanded item name (string) - */ - p.expandItemName = function(item) { - var name = item.name; - var key = item.key_; - - // extract params from key: - // "system.cpu.util[,system,avg1]" --> ["", "system", "avg1"] - var key_params = key.substring(key.indexOf('[') + 1, key.lastIndexOf(']')).split(','); - - // replace item parameters - for (var i = key_params.length; i >= 1; i--) { - name = name.replace('$' + i, key_params[i - 1]); - } - return name; - }; - return ZabbixAPI; }); From f7ded408d09ce891f23adede2c676077ea497f97 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sat, 11 Jul 2015 17:27:24 +0300 Subject: [PATCH 09/11] Added alert with explanations when limitmetrics parameter exceeded. --- zabbix/datasource.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index ccdebea..ab95d84 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -12,7 +12,7 @@ function (angular, _, kbn) { var module = angular.module('grafana.services'); - module.factory('ZabbixAPIDatasource', function($q, backendSrv, templateSrv, ZabbixAPI, zabbixHelperSrv) { + module.factory('ZabbixAPIDatasource', function($q, backendSrv, templateSrv, alertSrv, ZabbixAPI, zabbixHelperSrv) { /** * Datasource initialization. Calls when you refresh page, add @@ -122,6 +122,9 @@ function (angular, _, kbn) { // Don't perform query for high number of items // to prevent Grafana slowdown if (items.length > self.limitmetrics) { + var message = "Try to increase limitmetrics parameter in datasource config.
" + + "Current limitmetrics value is " + self.limitmetrics; + alertSrv.set("Metrics limit exceeded", message, "warning", 10000); return []; } else { items = _.flatten(items); From d716c266ba7dcd92c4f78c8ed618b96ff42a80f6 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sat, 11 Jul 2015 17:53:00 +0300 Subject: [PATCH 10/11] iss #36 - Some refactoring. --- zabbix/datasource.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index b57fefb..f001733 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -92,8 +92,7 @@ function (angular, _, kbn) { if (target.hostFilter && _.every(items, _.identity.hosts)) { // Use templated variables in filter - var pattern = templateSrv.replace(target.hostFilter); - var host_pattern = new RegExp(pattern); + var host_pattern = new RegExp(templateSrv.replace(target.hostFilter)); items = _.filter(items, function (item) { return _.some(item.hosts, function (host) { return host_pattern.test(host.name); @@ -108,8 +107,7 @@ function (angular, _, kbn) { if (target.itemFilter) { // Use templated variables in filter - var pattern = templateSrv.replace(target.itemFilter); - var item_pattern = new RegExp(pattern); + var item_pattern = new RegExp(templateSrv.replace(target.itemFilter)); return _.filter(items, function (item) { return item_pattern.test(zabbixHelperSrv.expandItemName(item)); }); From d20bd8e82178514584f929d09a6fadb822426128 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sun, 12 Jul 2015 11:32:51 +0300 Subject: [PATCH 11/11] Fixed #52 - Added Basic Auth support. --- zabbix/datasource.js | 4 +++- zabbix/zabbixAPIWrapper.js | 25 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/zabbix/datasource.js b/zabbix/datasource.js index f001733..f051866 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -23,6 +23,8 @@ function (angular, _, kbn) { function ZabbixAPIDatasource(datasource) { this.name = datasource.name; this.url = datasource.url; + this.basicAuth = datasource.basicAuth; + this.withCredentials = datasource.withCredentials; // TODO: fix passing username and password from config.html this.username = datasource.meta.username; @@ -36,7 +38,7 @@ function (angular, _, kbn) { this.limitmetrics = datasource.meta.limitmetrics || 100; // Initialize Zabbix API - this.zabbixAPI = new ZabbixAPI(this.url, this.username, this.password); + this.zabbixAPI = new ZabbixAPI(this.url, this.username, this.password, this.basicAuth, this.withCredentials); } /** diff --git a/zabbix/zabbixAPIWrapper.js b/zabbix/zabbixAPIWrapper.js index 626764a..9e9fb15 100644 --- a/zabbix/zabbixAPIWrapper.js +++ b/zabbix/zabbixAPIWrapper.js @@ -9,11 +9,13 @@ function (angular, _) { module.factory('ZabbixAPI', function($q, backendSrv) { - function ZabbixAPI(api_url, username, password) { + function ZabbixAPI(api_url, username, password, basicAuth, withCredentials) { // Initialize API parameters. - this.url = api_url; - this.username = username; - this.password = password; + this.url = api_url; + this.username = username; + this.password = password; + this.basicAuth = basicAuth; + this.withCredentials = withCredentials; } var p = ZabbixAPI.prototype; @@ -45,6 +47,13 @@ function (angular, _) { } }; + if (this.basicAuth || this.withCredentials) { + options.withCredentials = true; + } + if (this.basicAuth) { + options.headers.Authorization = this.basicAuth; + } + var self = this; return backendSrv.datasourceRequest(options).then(function (response) { if (!response.data) { @@ -88,6 +97,14 @@ function (angular, _) { }, }; + if (this.basicAuth || this.withCredentials) { + options.withCredentials = true; + } + if (this.basicAuth) { + options.headers = options.headers || {}; + options.headers.Authorization = this.basicAuth; + } + return backendSrv.datasourceRequest(options).then(function (result) { if (!result.data) { return null;