diff --git a/src/README.md b/src/README.md index 010b601..57f6e97 100644 --- a/src/README.md +++ b/src/README.md @@ -2,11 +2,9 @@ Zabbix plugin allows to show different type of data from [Zabbix](http://www.zabbix.com/) monitoring system. - - ### Live Demo -Check out the [live demo](http://play.grafana-zabbix.org/) +Check out the [live demo](http://play.grafana-zabbix.org/) with dashboard examples. ### Features diff --git a/src/dashboards/template_linux_server.json b/src/dashboards/template_linux_server.json new file mode 100644 index 0000000..3cb9afa --- /dev/null +++ b/src/dashboards/template_linux_server.json @@ -0,0 +1,569 @@ +{ + "id": null, + "title": "Template Linux Server", + "originalTitle": "Template Linux Server", + "tags": [ + "zabbix", + "example" + ], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": { + "CPU iowait time": "#B7DBAB", + "CPU system time": "#BF1B00", + "CPU user time": "#EAB839" + }, + "bars": false, + "datasource": null, + "editable": true, + "error": false, + "fill": 3, + "grid": { + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "application": { + "filter": "CPU" + }, + "functions": [], + "group": { + "filter": "$group" + }, + "host": { + "filter": "$host" + }, + "item": { + "filter": "/CPU/" + }, + "mode": 0, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "msResolution": false, + "shared": true, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "percent", + "logBase": 1, + "max": 100, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + "Processor load (1 min average per core)": "#1F78C1" + }, + "bars": false, + "datasource": null, + "editable": true, + "error": false, + "fill": 1, + "grid": { + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "application": { + "filter": "CPU" + }, + "functions": [], + "group": { + "filter": "$group" + }, + "host": { + "filter": "$host" + }, + "item": { + "filter": "Processor load (15 min average per core)" + }, + "mode": 0, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "System load", + "tooltip": { + "msResolution": false, + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "showTitle": true, + "title": "CPU" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": null, + "editable": true, + "error": false, + "fill": 3, + "grid": { + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "minSpan": 4, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": "netif", + "scopedVars": { + "netif": { + "text": "eth0", + "value": "eth0", + "selected": false + } + }, + "seriesOverrides": [ + { + "alias": "/Incoming/", + "transform": "negative-Y" + } + ], + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "application": { + "filter": "" + }, + "functions": [], + "group": { + "filter": "$group" + }, + "host": { + "filter": "$host" + }, + "item": { + "filter": "/$netif/" + }, + "mode": 0, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Network traffic on $netif", + "tooltip": { + "msResolution": false, + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "bps", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": null, + "editable": true, + "error": false, + "fill": 3, + "grid": { + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "minSpan": 4, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "scopedVars": { + "netif": { + "text": "eth1", + "value": "eth1", + "selected": false + } + }, + "seriesOverrides": [ + { + "alias": "/Incoming/", + "transform": "negative-Y" + } + ], + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "application": { + "filter": "" + }, + "functions": [], + "group": { + "filter": "$group" + }, + "host": { + "filter": "$host" + }, + "item": { + "filter": "/$netif/" + }, + "mode": 0, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Network traffic on $netif", + "tooltip": { + "msResolution": false, + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "bps", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "repeatIteration": 1460635040618, + "repeatPanelId": 3 + } + ], + "showTitle": true, + "title": "Network" + } + ], + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "3h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [ + { + "allFormat": "regex values", + "current": { + "text": "Frontend", + "value": "Frontend" + }, + "datasource": null, + "hide": 0, + "includeAll": false, + "label": "Group", + "multi": false, + "multiFormat": "glob", + "name": "group", + "options": [ + { + "text": "Backend", + "value": "Backend", + "selected": false + }, + { + "text": "Database servers", + "value": "Database servers", + "selected": false + }, + { + "text": "Frontend", + "value": "Frontend", + "selected": true + }, + { + "text": "Linux servers", + "value": "Linux servers", + "selected": false + }, + { + "text": "Network", + "value": "Network", + "selected": false + }, + { + "text": "Workstations", + "value": "Workstations", + "selected": false + }, + { + "text": "Zabbix servers", + "value": "Zabbix servers", + "selected": false + } + ], + "query": "*", + "refresh": 1, + "refresh_on_load": false, + "regex": "", + "type": "query" + }, + { + "allFormat": "glob", + "current": { + "text": "frontend01", + "value": "frontend01" + }, + "datasource": null, + "hide": 0, + "includeAll": false, + "label": "Host", + "multi": false, + "multiFormat": "glob", + "name": "host", + "options": [ + { + "text": "frontend01", + "value": "frontend01", + "selected": true + }, + { + "text": "frontend02", + "value": "frontend02", + "selected": false + } + ], + "query": "$group.*", + "refresh": 1, + "refresh_on_load": false, + "regex": "", + "type": "query" + }, + { + "allFormat": "regex values", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": null, + "hide": 0, + "hideLabel": false, + "includeAll": true, + "label": "Network interface", + "multi": true, + "multiFormat": "regex values", + "name": "netif", + "options": [ + { + "text": "All", + "value": "$__all", + "selected": true + }, + { + "text": "eth0", + "value": "eth0", + "selected": false + }, + { + "text": "eth1", + "value": "eth1", + "selected": false + } + ], + "query": "*.$host.Network interfaces.*", + "refresh": 1, + "refresh_on_load": false, + "regex": "/(?:Incoming|Outgoing) network traffic on (.*)/", + "type": "query" + } + ] + }, + "annotations": { + "list": [] + }, + "schemaVersion": 12, + "version": 8, + "links": [] +} diff --git a/src/dashboards/zabbix_server_dashboard.json b/src/dashboards/zabbix_server_dashboard.json index 4f68e52..b9a8cb0 100644 --- a/src/dashboards/zabbix_server_dashboard.json +++ b/src/dashboards/zabbix_server_dashboard.json @@ -249,7 +249,20 @@ "pointradius": 5, "points": false, "renderer": "flot", - "seriesOverrides": [], + "seriesOverrides": [ + { + "alias": "/user/", + "color": "#1F78C1" + }, + { + "alias": "/system/", + "color": "#BF1B00" + }, + { + "alias": "/iowait/", + "color": "#E5AC0E" + } + ], "span": 7, "stack": true, "steppedLine": false, @@ -286,7 +299,7 @@ }, "yaxes": [ { - "format": "short", + "format": "percent", "label": null, "logBase": 1, "max": null, @@ -324,7 +337,7 @@ "scroll": true, "showHeader": true, "sort": { - "col": 0, + "col": 2, "desc": true }, "span": 5, @@ -335,17 +348,20 @@ "type": "date" }, { - "colorMode": null, + "colorMode": "cell", "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" + "rgb(41, 170, 106)", + "rgba(239, 148, 21, 0.89)", + "rgba(239, 10, 10, 0.9)" ], - "decimals": 2, + "decimals": 1, "pattern": "/.*/", - "thresholds": [], + "thresholds": [ + "50", + "80" + ], "type": "number", - "unit": "short" + "unit": "percent" } ], "targets": [ @@ -373,6 +389,207 @@ } ], "title": "Row" + }, + { + "title": "New row", + "height": "380", + "editable": true, + "collapse": false, + "panels": [ + { + "title": "Zabbix busy processes", + "error": false, + "span": 7.069277691711851, + "editable": true, + "type": "graph", + "isNew": true, + "id": 6, + "targets": [ + { + "refId": "A", + "mode": 0, + "group": { + "filter": "Zabbix servers" + }, + "host": { + "filter": "Zabbix server" + }, + "application": { + "filter": "Zabbix server" + }, + "item": { + "filter": "/Zabbix busy/" + }, + "functions": [] + } + ], + "datasource": null, + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "percent" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true + }, + "grid": { + "threshold1": null, + "threshold2": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "lines": true, + "fill": 0, + "linewidth": 2, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": false, + "min": false, + "max": false, + "current": false, + "total": false, + "avg": false, + "hideEmpty": true, + "hideZero": true, + "alignAsTable": true, + "rightSide": true + }, + "nullPointMode": "connected", + "steppedLine": false, + "tooltip": { + "value_type": "cumulative", + "shared": true, + "msResolution": false + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "links": [] + }, + { + "title": "Zabbix Queue", + "error": false, + "span": 4.930722308288148, + "editable": true, + "type": "graph", + "isNew": true, + "id": 7, + "targets": [ + { + "refId": "A", + "mode": 0, + "group": { + "filter": "Zabbix servers" + }, + "host": { + "filter": "Zabbix server" + }, + "application": { + "filter": "Zabbix server" + }, + "item": { + "filter": "Zabbix queue" + }, + "functions": [] + }, + { + "refId": "B", + "mode": 0, + "group": { + "filter": "Zabbix servers" + }, + "host": { + "filter": "Zabbix server" + }, + "application": { + "filter": "Zabbix server" + }, + "item": { + "filter": "/Values processed/" + }, + "functions": [] + } + ], + "datasource": null, + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true + }, + "grid": { + "threshold1": null, + "threshold2": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "lines": true, + "fill": 0, + "linewidth": 2, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": false, + "min": false, + "max": false, + "current": false, + "total": false, + "avg": false + }, + "nullPointMode": "connected", + "steppedLine": false, + "tooltip": { + "value_type": "cumulative", + "shared": true, + "msResolution": false + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "links": [] + } + ] } ], "time": { @@ -411,6 +628,6 @@ "list": [] }, "schemaVersion": 12, - "version": 5, + "version": 6, "links": [] } diff --git a/src/datasource-zabbix/datasource.js b/src/datasource-zabbix/datasource.js index 4c7ccfd..a3f1f12 100644 --- a/src/datasource-zabbix/datasource.js +++ b/src/datasource-zabbix/datasource.js @@ -57,46 +57,6 @@ export class ZabbixAPIDatasource { // Datasource methods // //////////////////////// - /** - * Test connection to Zabbix API - * @return {object} Connection status and Zabbix API version - */ - testDatasource() { - var self = this; - return this.zabbixAPI.getVersion().then(function (version) { - return self.zabbixAPI.login().then(function (auth) { - if (auth) { - return { - status: "success", - title: "Success", - message: "Zabbix API version: " + version - }; - } else { - return { - status: "error", - title: "Invalid user name or password", - message: "Zabbix API version: " + version - }; - } - }, function(error) { - console.log(error); - return { - status: "error", - title: "Connection failed", - message: error - }; - }); - }, - function(error) { - console.log(error); - return { - status: "error", - title: "Connection failed", - message: "Could not connect to given url" - }; - }); - } - /** * Query panel data. Calls for each panel in dashboard. * @param {Object} options Contains time range, targets and other info. @@ -106,12 +66,13 @@ export class ZabbixAPIDatasource { var self = this; // get from & to in seconds - var from = Math.ceil(dateMath.parse(options.range.from) / 1000); - var to = Math.ceil(dateMath.parse(options.range.to) / 1000); + var timeFrom = Math.ceil(dateMath.parse(options.range.from) / 1000); + var timeTo = Math.ceil(dateMath.parse(options.range.to) / 1000); var useTrendsFrom = Math.ceil(dateMath.parse('now-' + this.trendsFrom) / 1000); + var useTrends = (timeFrom < useTrendsFrom) && this.trends; // Create request for each target - var promises = _.map(options.targets, function(target) { + var promises = _.map(options.targets, target => { if (target.mode !== 1) { @@ -119,8 +80,7 @@ export class ZabbixAPIDatasource { target = migrations.migrate(target); // Don't request undefined and hidden targets - if (target.hide || !target.group || - !target.host || !target.item) { + if (target.hide || !target.group || !target.host || !target.item) { return []; } @@ -132,116 +92,14 @@ export class ZabbixAPIDatasource { // Query numeric data if (!target.mode || target.mode === 0) { - - // Build query in asynchronous manner - return self.queryProcessor - .build(groupFilter, hostFilter, appFilter, itemFilter, 'num') - .then(items => { - // Add hostname for items from multiple hosts - var addHostName = utils.isRegex(target.host.filter); - var getHistory; - - // Use trends - if ((from < useTrendsFrom) && self.trends) { - - // Find trendValue() function and get specified trend value - var trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name'); - var trendValueFunc = _.find(target.functions, function(func) { - return _.contains(trendFunctions, func.def.name); - }); - var valueType = trendValueFunc ? trendValueFunc.params[0] : "avg"; - - getHistory = self.zabbixAPI.getTrend(items, from, to).then(function(history) { - return self.queryProcessor.handleTrends(history, items, addHostName, valueType); - }); - } else { - - // Use history - getHistory = self.zabbixCache.getHistory(items, from, to).then(function(history) { - return self.queryProcessor.handleHistory(history, items, addHostName); - }); - } - - return getHistory.then(function (timeseries_data) { - timeseries_data = _.map(timeseries_data, function (timeseries) { - - // Filter only transform functions - var transformFunctions = bindFunctionDefs(target.functions, 'Transform', DataProcessor); - - // Metric data processing - var dp = timeseries.datapoints; - for (var i = 0; i < transformFunctions.length; i++) { - dp = transformFunctions[i](dp); - } - timeseries.datapoints = dp; - - return timeseries; - }); - - // Aggregations - var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate', DataProcessor); - var dp = _.map(timeseries_data, 'datapoints'); - if (aggregationFunctions.length) { - for (var i = 0; i < aggregationFunctions.length; i++) { - dp = aggregationFunctions[i](dp); - } - var lastAgg = _.findLast(target.functions, function(func) { - return _.contains( - _.map(metricFunctions.getCategories()['Aggregate'], 'name'), func.def.name); - }); - timeseries_data = [{ - target: lastAgg.text, - datapoints: dp - }]; - } - - // Apply alias functions - var aliasFunctions = bindFunctionDefs(target.functions, 'Alias', DataProcessor); - for (var j = 0; j < aliasFunctions.length; j++) { - _.each(timeseries_data, aliasFunctions[j]); - } - - return timeseries_data; - }); - }); + return self.queryNumericData(target, groupFilter, hostFilter, appFilter, itemFilter, + timeFrom, timeTo, useTrends, options, self); } // Query text data else if (target.mode === 2) { - return self.queryProcessor - .build(groupFilter, hostFilter, appFilter, itemFilter, 'text') - .then(items => { - if (items.length) { - var textItemsPromises = _.map(items, item => { - return self.zabbixAPI.getLastValue(item.itemid); - }); - return self.q.all(textItemsPromises) - .then(result => { - return _.map(result, (lastvalue, index) => { - var extractedValue; - if (target.textFilter) { - var text_extract_pattern = new RegExp(self.replaceTemplateVars(target.textFilter, options.scopedVars)); - extractedValue = text_extract_pattern.exec(lastvalue); - if (extractedValue) { - if (target.useCaptureGroups) { - extractedValue = extractedValue[1]; - } else { - extractedValue = extractedValue[0]; - } - } - } else { - extractedValue = lastvalue; - } - return { - target: items[index].name, - datapoints: [[extractedValue, to * 1000]] - }; - }); - }); - } else { - return self.q.when([]); - } - }); + return self.queryTextData(target, groupFilter, hostFilter, appFilter, itemFilter, + timeFrom, timeTo, options, self); } } @@ -250,25 +108,27 @@ export class ZabbixAPIDatasource { // Don't show undefined and hidden targets if (target.hide || !target.itservice || !target.slaProperty) { return []; - } else { - return this.zabbixAPI.getSLA(target.itservice.serviceid, from, to) - .then(slaObject => { - return self.queryProcessor.handleSLAResponse(target.itservice, target.slaProperty, slaObject); - }); } + + return this.zabbixAPI + .getSLA(target.itservice.serviceid, timeFrom, timeTo) + .then(slaObject => { + return self.queryProcessor + .handleSLAResponse(target.itservice, target.slaProperty, slaObject); + }); } }, this); // Data for panel (all targets) return this.q.all(_.flatten(promises)) .then(_.flatten) - .then(function (timeseries_data) { + .then(timeseries_data => { // Series downsampling - var data = _.map(timeseries_data, function(timeseries) { + var data = _.map(timeseries_data, timeseries => { if (timeseries.datapoints.length > options.maxDataPoints) { - timeseries.datapoints = - DataProcessor.groupBy(options.interval, DataProcessor.AVERAGE, timeseries.datapoints); + timeseries.datapoints = DataProcessor + .groupBy(options.interval, DataProcessor.AVERAGE, timeseries.datapoints); } return timeseries; }); @@ -276,6 +136,166 @@ export class ZabbixAPIDatasource { }); } + queryNumericData(target, groupFilter, hostFilter, appFilter, itemFilter, timeFrom, timeTo, useTrends, options, self) { + // Build query in asynchronous manner + return self.queryProcessor + .build(groupFilter, hostFilter, appFilter, itemFilter, 'num') + .then(items => { + // Add hostname for items from multiple hosts + var addHostName = utils.isRegex(target.host.filter); + var getHistory; + + // Use trends + if (useTrends) { + + // Find trendValue() function and get specified trend value + var trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name'); + var trendValueFunc = _.find(target.functions, func => { + return _.contains(trendFunctions, func.def.name); + }); + var valueType = trendValueFunc ? trendValueFunc.params[0] : "avg"; + + getHistory = self.zabbixAPI + .getTrend(items, timeFrom, timeTo) + .then(history => { + return self.queryProcessor.handleTrends(history, items, addHostName, valueType); + }); + } + + // Use history + else { + getHistory = self.zabbixCache + .getHistory(items, timeFrom, timeTo) + .then(history => { + return self.queryProcessor.handleHistory(history, items, addHostName); + }); + } + + return getHistory.then(timeseries_data => { + + // Apply transformation functions + timeseries_data = _.map(timeseries_data, timeseries => { + + // Filter only transform functions + var transformFunctions = bindFunctionDefs(target.functions, 'Transform', DataProcessor); + + // Metric data processing + var dp = timeseries.datapoints; + for (var i = 0; i < transformFunctions.length; i++) { + dp = transformFunctions[i](dp); + } + timeseries.datapoints = dp; + + return timeseries; + }); + + // Apply aggregations + var aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate', DataProcessor); + var dp = _.map(timeseries_data, 'datapoints'); + if (aggregationFunctions.length) { + for (var i = 0; i < aggregationFunctions.length; i++) { + dp = aggregationFunctions[i](dp); + } + var lastAgg = _.findLast(target.functions, func => { + return _.contains( + _.map(metricFunctions.getCategories()['Aggregate'], 'name'), func.def.name); + }); + timeseries_data = [ + { + target: lastAgg.text, + datapoints: dp + } + ]; + } + + // Apply alias functions + var aliasFunctions = bindFunctionDefs(target.functions, 'Alias', DataProcessor); + for (var j = 0; j < aliasFunctions.length; j++) { + _.each(timeseries_data, aliasFunctions[j]); + } + + return timeseries_data; + }); + }); + } + + queryTextData(target, groupFilter, hostFilter, appFilter, itemFilter, timeFrom, timeTo, options, self) { + return self.queryProcessor + .build(groupFilter, hostFilter, appFilter, itemFilter, 'text') + .then(items => { + if (items.length) { + var textItemsPromises = _.map(items, item => { + return self.zabbixAPI.getLastValue(item.itemid); + }); + return self.q.all(textItemsPromises) + .then(result => { + return _.map(result, (lastvalue, index) => { + var extractedValue; + if (target.textFilter) { + var text_extract_pattern = new RegExp(self.replaceTemplateVars(target.textFilter, options.scopedVars)); + extractedValue = text_extract_pattern.exec(lastvalue); + if (extractedValue) { + if (target.useCaptureGroups) { + extractedValue = extractedValue[1]; + } else { + extractedValue = extractedValue[0]; + } + } + } else { + extractedValue = lastvalue; + } + return { + target: items[index].name, + datapoints: [[extractedValue, timeTo * 1000]] + }; + }); + }); + } else { + return self.q.when([]); + } + }); + } + + /** + * Test connection to Zabbix API + * @return {object} Connection status and Zabbix API version + */ + testDatasource() { + var self = this; + return this.zabbixAPI.getVersion() + .then(version => { + return self.zabbixAPI.login() + .then(auth => { + if (auth) { + return { + status: "success", + title: "Success", + message: "Zabbix API version: " + version + }; + } else { + return { + status: "error", + title: "Invalid user name or password", + message: "Zabbix API version: " + version + }; + } + }, error => { + return { + status: "error", + title: error.message, + message: error.data + }; + }); + }, error => { + console.log(error); + return { + status: "error", + title: "Connection failed", + message: "Could not connect to given url" + }; + }); + } + //////////////// // Templating // //////////////// @@ -309,30 +329,35 @@ export class ZabbixAPIDatasource { if (template.app === '/.*/') { template.app = ''; } - return this.queryProcessor.getItems(template.group, template.host, template.app) - .then(function(items) { + return this.queryProcessor + .getItems(template.group, template.host, template.app) + .then(items => { return _.map(items, formatMetric); }); } // Get applications else if (parts.length === 3) { - return this.queryProcessor.getApps(template.group, template.host) - .then(function(apps) { + return this.queryProcessor + .getApps(template.group, template.host) + .then(apps => { return _.map(apps, formatMetric); }); } // Get hosts else if (parts.length === 2) { - return this.queryProcessor.getHosts(template.group) - .then(function(hosts) { + return this.queryProcessor + .getHosts(template.group) + .then(hosts => { return _.map(hosts, formatMetric); }); } // Get groups else if (parts.length === 1) { - return this.zabbixCache.getGroups(template.group).then(function(groups) { - return _.map(groups, formatMetric); - }); + return this.zabbixCache + .getGroups(template.group) + .then(groups => { + return _.map(groups, formatMetric); + }); } // Return empty object for invalid request else { @@ -348,66 +373,66 @@ export class ZabbixAPIDatasource { var timeFrom = Math.ceil(dateMath.parse(options.rangeRaw.from) / 1000); var timeTo = Math.ceil(dateMath.parse(options.rangeRaw.to) / 1000); var annotation = options.annotation; - var self = this; var showOkEvents = annotation.showOkEvents ? [0, 1] : 1; // Show all triggers var showTriggers = [0, 1]; - var buildQuery = self.queryProcessor.buildTriggerQuery(this.replaceTemplateVars(annotation.group, {}), - this.replaceTemplateVars(annotation.host, {}), - this.replaceTemplateVars(annotation.application, {})); - return buildQuery.then(function(query) { - return self.zabbixAPI.getTriggers(query.groupids, - query.hostids, - query.applicationids, - showTriggers, - timeFrom, timeTo) - .then(function(triggers) { + var buildQuery = this.queryProcessor + .buildTriggerQuery(this.replaceTemplateVars(annotation.group, {}), + this.replaceTemplateVars(annotation.host, {}), + this.replaceTemplateVars(annotation.application, {})); + var self = this; + return buildQuery.then(query => { + return self.zabbixAPI + .getTriggers(query.groupids, query.hostids, query.applicationids, + showTriggers, timeFrom, timeTo) + .then(triggers => { // Filter triggers by description if (utils.isRegex(annotation.trigger)) { - triggers = _.filter(triggers, function(trigger) { + triggers = _.filter(triggers, trigger => { return utils.buildRegex(annotation.trigger).test(trigger.description); }); } else if (annotation.trigger) { - triggers = _.filter(triggers, function(trigger) { + triggers = _.filter(triggers, trigger => { return trigger.description === annotation.trigger; }); } // Remove events below the chose severity - triggers = _.filter(triggers, function(trigger) { + triggers = _.filter(triggers, trigger => { return Number(trigger.priority) >= Number(annotation.minseverity); }); var objectids = _.map(triggers, 'triggerid'); - return self.zabbixAPI.getEvents(objectids, timeFrom, timeTo, showOkEvents) - .then(function (events) { + return self.zabbixAPI + .getEvents(objectids, timeFrom, timeTo, showOkEvents) + .then(events => { var indexedTriggers = _.indexBy(triggers, 'triggerid'); // Hide acknowledged events if option enabled if (annotation.hideAcknowledged) { - events = _.filter(events, function(event) { + events = _.filter(events, event => { return !event.acknowledges.length; }); } - return _.map(events, function(e) { + return _.map(events, event => { var title =''; if (annotation.showHostname) { - title += e.hosts[0].name + ': '; + title += event.hosts[0].name + ': '; } // Show event type (OK or Problem) - title += Number(e.value) ? 'Problem' : 'OK'; + title += Number(event.value) ? 'Problem' : 'OK'; - var formatted_acknowledges = utils.formatAcknowledges(e.acknowledges); + var formatted_acknowledges = utils.formatAcknowledges(event.acknowledges); return { annotation: annotation, - time: e.clock * 1000, + time: event.clock * 1000, title: title, - text: indexedTriggers[e.objectid].description + formatted_acknowledges + text: indexedTriggers[event.objectid].description + formatted_acknowledges }; }); }); diff --git a/src/datasource-zabbix/partials/query.editor.html b/src/datasource-zabbix/partials/query.editor.html index 72f6b73..50342cd 100644 --- a/src/datasource-zabbix/partials/query.editor.html +++ b/src/datasource-zabbix/partials/query.editor.html @@ -89,7 +89,6 @@ - - - -
@@ -156,7 +135,6 @@ { - return '$' + variable.name; - }); - return _.contains(variables, str); - } else { - return false; - } + return utils.isTemplateVariable(str, this.templateSrv.variables); } onTargetBlur() { diff --git a/src/datasource-zabbix/utils.js b/src/datasource-zabbix/utils.js index 77ca3bc..5925da0 100644 --- a/src/datasource-zabbix/utils.js +++ b/src/datasource-zabbix/utils.js @@ -29,6 +29,18 @@ export function isRegex(str) { return regexPattern.test(str); } +export function isTemplateVariable(str, templateVariables) { + var variablePattern = /^\$\w+/; + if (variablePattern.test(str)) { + var variables = _.map(templateVariables, variable => { + return '$' + variable.name; + }); + return _.contains(variables, str); + } else { + return false; + } +} + export function buildRegex(str) { var matches = str.match(regexPattern); var pattern = matches[1]; diff --git a/src/panel-triggers/editor.html b/src/panel-triggers/editor.html index fc55d3e..069da01 100644 --- a/src/panel-triggers/editor.html +++ b/src/panel-triggers/editor.html @@ -10,12 +10,14 @@ + ng-class="{ + 'zbx-variable': editor.isVariable(editor.panel.triggers.group.filter), + 'zbx-regex': editor.isRegex(editor.panel.triggers.group.filter) + }">