diff --git a/README.md b/README.md index 1585da6..e96ecff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ # grafana-zabbix Zabbix API datasource for Grafana dashboard +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7454206/34bf9f8c-f27a-11e4-8e96-a73829f188c4.png) + + +Query editor allows to add metric by step-by-step selection from host group, host, application dropdown menus. + +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7441162/4f6af788-f0e4-11e4-887b-34d987d00c40.png) +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7441163/56f28f16-f0e4-11e4-9d46-54181c2a2e7e.png) +![alt tag](https://cloud.githubusercontent.com/assets/4932851/7441167/5f29cc94-f0e4-11e4-8d39-7580f33201f6.png) + + ## Installation ### Grafana 1.9.x @@ -30,4 +40,4 @@ Download latest release and unpack into `/plugins/dat ``` ### Grafana 2.0.x -Now in development. \ No newline at end of file +Now in development. diff --git a/zabbix/datasource.js b/zabbix/datasource.js index bbf1820..ad4ccc0 100644 --- a/zabbix/datasource.js +++ b/zabbix/datasource.js @@ -35,9 +35,11 @@ function (angular, _, kbn) { // get from & to in seconds var from = kbn.parseDate(options.range.from).getTime(); var to = kbn.parseDate(options.range.to).getTime(); + // Need for find target alias var targets = options.targets; + // TODO: remove undefined targets from request // Check that all targets defined var targetsDefined = options.targets.every(function (target, index, array) { return target.item; @@ -46,7 +48,6 @@ function (angular, _, kbn) { // Extract zabbix api item objects from targets var target_items = _.map(options.targets, 'item'); } else { - // No valid targets, return the empty dataset var d = $q.defer(); d.resolve({ data: [] }); @@ -56,20 +57,7 @@ function (angular, _, kbn) { from = Math.ceil(from/1000); to = Math.ceil(to/1000); - var performedQuery; - - // Check authorization first - if (!this.auth) { - var self = this; - performedQuery = this.performZabbixAPILogin().then(function (response) { - self.auth = response; - return self.performTimeSeriesQuery(target_items, from, to); - }); - } else { - performedQuery = this.performTimeSeriesQuery(target_items, from, to); - } - - return performedQuery.then(function (response) { + return this.performTimeSeriesQuery(target_items, from, to).then(function (response) { /** * Response should be in the format: * data: [ @@ -85,9 +73,7 @@ function (angular, _, kbn) { */ // Index returned datapoints by item/metric id - var indexed_result = _.groupBy(response.data.result, function (history_item) { - return history_item.itemid; - }); + var indexed_result = _.groupBy(response, 'itemid'); // Reduce timeseries to the same size for stacking and tooltip work properly var min_length = _.min(_.map(indexed_result, function (history) { @@ -137,6 +123,9 @@ function (angular, _, kbn) { ZabbixAPIDatasource.prototype.doZabbixAPIRequest = function(request_data) { var options = { method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, url: this.url, data: request_data }; @@ -171,37 +160,68 @@ function (angular, _, kbn) { * @param items: array of zabbix api item objects */ ZabbixAPIDatasource.prototype.performTimeSeriesQuery = function(items, start, end) { - var item_ids = items.map(function (item, index, array) { - return item.itemid; - }); - // TODO: if different value types passed? - // Perform multiple api request. - var hystory_type = items[0].value_type; - var options = { - method: 'POST', - url: this.url, - data: { + + // Group items by value type for separate requests + var items_by_value_type = _.groupBy(items, 'value_type'); + + var self = this; + var apiRequests = []; + + // Prepare requests for each value type + _.each(items_by_value_type, function (value, key, list) { + var item_ids = _.map(value, 'itemid'); + var history_type = key; + var data = { jsonrpc: '2.0', method: 'history.get', params: { - output: 'extend', - history: hystory_type, - itemids: item_ids, - sortfield: 'clock', - sortorder: 'ASC', - limit: this.limitmetrics, - time_from: start, + output: 'extend', + history: history_type, + itemids: item_ids, + sortfield: 'clock', + sortorder: 'ASC', + limit: self.limitmetrics, + time_from: start, }, - auth: this.auth, + auth: self.auth, id: 1 - }, - }; - // Relative queries (e.g. last hour) don't include an end time - if (end) { - options.data.params.time_till = end; - } + }; - return $http(options); + // Relative queries (e.g. last hour) don't include an end time + if (end) { + data.params.time_till = end; + } + + apiRequests.push(self.doZabbixAPIRequest(data)); + }); + + return this.handleMultipleRequest(apiRequests); + }; + + + // Handle multiple request + ZabbixAPIDatasource.prototype.handleMultipleRequest = function(apiRequests) { + var history = []; + var performedQuery = null; + + // Build chain of api requests and put all history data into single array + _.each(apiRequests, function (apiRequest) { + if(!performedQuery) { + performedQuery = apiRequest.then(function (response) { + history = history.concat(response); + return history; + }); + } else { + performedQuery = performedQuery.then(function () { + return apiRequest.then(function (response) { + history = history.concat(response); + return history; + }); + }); + } + }); + + return performedQuery; }; @@ -238,6 +258,7 @@ function (angular, _, kbn) { method: 'hostgroup.get', params: { output: ['name'], + real_hosts: true, //Return only host groups that contain hosts sortfield: 'name' }, auth: this.auth, @@ -294,7 +315,11 @@ function (angular, _, kbn) { params: { output: ['name', 'key_', 'value_type', 'delay'], sortfield: 'name', - hostids: hostid + hostids: hostid, + webitems: true, //Include web items in the result + filter: { + value_type: [0,3] + } }, auth: this.auth, id: 1 diff --git a/zabbix/queryCtrl.js b/zabbix/queryCtrl.js index 29b1192..e367f49 100644 --- a/zabbix/queryCtrl.js +++ b/zabbix/queryCtrl.js @@ -135,7 +135,6 @@ function (angular, _) { $scope.metric.hostGroupList = series; if ($scope.target.hostGroup) { $scope.target.hostGroup = $scope.metric.hostGroupList.filter(function (item, index, array) { - // Find selected host in metric.hostList return (item.groupid == $scope.target.hostGroup.groupid); }).pop(); @@ -150,11 +149,13 @@ function (angular, _) { $scope.updateHostList = function(groupid) { $scope.datasource.performHostSuggestQuery(groupid).then(function (series) { $scope.metric.hostList = series; - $scope.target.host = $scope.metric.hostList.filter(function (item, index, array) { - // Find selected host in metric.hostList - return (item.hostid == $scope.target.host.hostid); - }).pop(); + if ($scope.target.host) { + $scope.target.host = $scope.metric.hostList.filter(function (item, index, array) { + // Find selected host in metric.hostList + return (item.hostid == $scope.target.host.hostid); + }).pop(); + } }); }; @@ -167,7 +168,6 @@ function (angular, _) { $scope.metric.applicationList = series; if ($scope.target.application) { $scope.target.application = $scope.metric.applicationList.filter(function (item, index, array) { - // Find selected application in metric.hostList return (item.applicationid == $scope.target.application.applicationid); }).pop(); @@ -192,11 +192,12 @@ function (angular, _) { item.expandedName = expandItemName(item); } }); - $scope.target.item = $scope.metric.itemList.filter(function (item, index, array) { - - // Find selected item in metric.hostList - return (item.itemid == $scope.target.item.itemid); - }).pop(); + if ($scope.target.item) { + $scope.target.item = $scope.metric.itemList.filter(function (item, index, array) { + // Find selected item in metric.hostList + return (item.itemid == $scope.target.item.itemid); + }).pop(); + } }); } else { $scope.metric.itemList = [];