Merge branch 'develop'
This commit is contained in:
@@ -25,6 +25,10 @@ function (angular, _, kbn) {
|
|||||||
this.username = datasource.meta.username;
|
this.username = datasource.meta.username;
|
||||||
this.password = datasource.meta.password;
|
this.password = datasource.meta.password;
|
||||||
|
|
||||||
|
// Use trends instead history since specified time
|
||||||
|
this.trends = datasource.meta.trends;
|
||||||
|
this.trendsFrom = datasource.meta.trendsFrom || '7d';
|
||||||
|
|
||||||
// Limit metrics per panel for templated request
|
// Limit metrics per panel for templated request
|
||||||
this.limitmetrics = datasource.meta.limitmetrics || 50;
|
this.limitmetrics = datasource.meta.limitmetrics || 50;
|
||||||
}
|
}
|
||||||
@@ -44,6 +48,7 @@ function (angular, _, kbn) {
|
|||||||
// get from & to in seconds
|
// get from & to in seconds
|
||||||
var from = Math.ceil(kbn.parseDate(options.range.from).getTime() / 1000);
|
var from = Math.ceil(kbn.parseDate(options.range.from).getTime() / 1000);
|
||||||
var to = Math.ceil(kbn.parseDate(options.range.to).getTime() / 1000);
|
var to = Math.ceil(kbn.parseDate(options.range.to).getTime() / 1000);
|
||||||
|
var useTrendsFrom = Math.ceil(kbn.parseDate('now-' + this.trendsFrom).getTime() / 1000);
|
||||||
|
|
||||||
// Create request for each target
|
// Create request for each target
|
||||||
var promises = _.map(options.targets, function(target) {
|
var promises = _.map(options.targets, function(target) {
|
||||||
@@ -93,9 +98,15 @@ function (angular, _, kbn) {
|
|||||||
return [];
|
return [];
|
||||||
} else {
|
} else {
|
||||||
items = _.flatten(items);
|
items = _.flatten(items);
|
||||||
|
|
||||||
|
if ((from < useTrendsFrom) && self.trends) {
|
||||||
|
return self.getTrends(items, from, to)
|
||||||
|
.then(_.partial(self.handleTrendResponse, items));
|
||||||
|
} else {
|
||||||
return self.performTimeSeriesQuery(items, from, to)
|
return self.performTimeSeriesQuery(items, from, to)
|
||||||
.then(_.partial(self.handleHistoryResponse, items));
|
.then(_.partial(self.handleHistoryResponse, items));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
@@ -142,6 +153,58 @@ function (angular, _, kbn) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ZabbixAPIDatasource.prototype.getTrends = function(items, start, end) {
|
||||||
|
// Group items by value type
|
||||||
|
var grouped_items = _.groupBy(items, 'value_type');
|
||||||
|
|
||||||
|
// Perform request for each value type
|
||||||
|
return $q.all(_.map(grouped_items, function (items, value_type) {
|
||||||
|
var itemids = _.map(items, 'itemid');
|
||||||
|
var params = {
|
||||||
|
output: 'extend',
|
||||||
|
trend: value_type,
|
||||||
|
itemids: itemids,
|
||||||
|
sortfield: 'clock',
|
||||||
|
sortorder: 'ASC',
|
||||||
|
time_from: start
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (end) {
|
||||||
|
params.time_till = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.performZabbixAPIRequest('trend.get', params);
|
||||||
|
}, this)).then(function (results) {
|
||||||
|
return _.flatten(results);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ZabbixAPIDatasource.prototype.handleTrendResponse = function(items, trends) {
|
||||||
|
|
||||||
|
// Group items and trends by itemid
|
||||||
|
var indexed_items = _.indexBy(items, 'itemid');
|
||||||
|
var grouped_history = _.groupBy(trends, 'itemid');
|
||||||
|
|
||||||
|
return $q.when(_.map(grouped_history, function (trends, itemid) {
|
||||||
|
var item = indexed_items[itemid];
|
||||||
|
var series = {
|
||||||
|
target: (item.hosts ? item.hosts[0].name+': ' : '') + expandItemName(item),
|
||||||
|
datapoints: _.map(trends, function (p) {
|
||||||
|
|
||||||
|
// Value must be a number for properly work
|
||||||
|
var value = Number(p.value_avg);
|
||||||
|
return [value, p.clock * 1000];
|
||||||
|
})
|
||||||
|
};
|
||||||
|
return series;
|
||||||
|
})).then(function (result) {
|
||||||
|
return _.sortBy(result, 'target');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Zabbix API data to Grafana format
|
* Convert Zabbix API data to Grafana format
|
||||||
*
|
*
|
||||||
@@ -618,31 +681,37 @@ function (angular, _, kbn) {
|
|||||||
search: {
|
search: {
|
||||||
'description': annotation.query
|
'description': annotation.query
|
||||||
},
|
},
|
||||||
|
searchWildcardsEnabled: true,
|
||||||
|
expandDescription: true
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.performZabbixAPIRequest('trigger.get', params)
|
return this.performZabbixAPIRequest('trigger.get', params)
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
if(result) {
|
if(result) {
|
||||||
var obs = {};
|
var objects = _.indexBy(result, 'triggerid');
|
||||||
obs = _.indexBy(result, 'triggerid');
|
|
||||||
|
|
||||||
var params = {
|
var params = {
|
||||||
output: 'extend',
|
output: 'extend',
|
||||||
sortorder: 'DESC',
|
|
||||||
time_from: from,
|
time_from: from,
|
||||||
time_till: to,
|
time_till: to,
|
||||||
objectids: _.keys(obs)
|
objectids: _.keys(objects),
|
||||||
|
select_acknowledges: 'extend'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Show problem events only
|
||||||
|
if (!annotation.showOkEvents) {
|
||||||
|
params.value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return self.performZabbixAPIRequest('event.get', params)
|
return self.performZabbixAPIRequest('event.get', params)
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
var events = [];
|
var events = [];
|
||||||
_.each(result, function(e) {
|
_.each(result, function(e) {
|
||||||
|
var formatted_acknowledges = formatAcknowledges(e.acknowledges);;
|
||||||
events.push({
|
events.push({
|
||||||
annotation: annotation,
|
annotation: annotation,
|
||||||
time: e.clock * 1000,
|
time: e.clock * 1000,
|
||||||
title: obs[e.objectid].description,
|
title: Number(e.value) ? 'Problem' : 'OK',
|
||||||
text: e.eventid,
|
text: objects[e.objectid].description + formatted_acknowledges,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return events;
|
return events;
|
||||||
@@ -692,4 +761,44 @@ function expandItemName(item) {
|
|||||||
name = name.replace('$' + i, key_params[i - 1]);
|
name = name.replace('$' + i, key_params[i - 1]);
|
||||||
};
|
};
|
||||||
return name;
|
return name;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = '<br><br>Acknowledges:<br><table><tr><td><b>Time</b></td><td><b>User</b></td><td><b>Comments</b></td></tr>';
|
||||||
|
_.each(_.map(acknowledges, function (ack) {
|
||||||
|
var time = new Date(ack.clock * 1000);
|
||||||
|
return '<tr><td><i>' + getShortTime(time) + '</i></td><td>' + ack.alias + ' (' + ack.name+ ' ' + ack.surname + ')' + '</td><td>' + ack.message + '</td></tr>';
|
||||||
|
}), function (ack) {
|
||||||
|
formatted_acknowledges = formatted_acknowledges.concat(ack)
|
||||||
|
});
|
||||||
|
formatted_acknowledges = formatted_acknowledges.concat('</table>')
|
||||||
|
return formatted_acknowledges;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,15 @@
|
|||||||
<div class="section">
|
<div class="section">
|
||||||
<h5>Zabbix trigger <tip>Example: Lack of free swap space</tip></h5>
|
<h5>Zabbix trigger <tip>Example: Lack of free swap space</tip></h5>
|
||||||
<div class="editor-option">
|
<div class="editor-option">
|
||||||
<input type="text" class="span10" ng-model='currentAnnotation.query' placeholder="Lack of free swap space"></input>
|
<input type="text" class="span10" ng-model="currentAnnotation.query" placeholder="Lack of free swap space"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-row">
|
||||||
|
<div class="section">
|
||||||
|
<h5>Options</h5>
|
||||||
|
<input type="checkbox" class="cr1" id="currentAnnotation.showOkEvents" ng-model="currentAnnotation.showOkEvents" ng-checked="currentAnnotation.showOkEvents">
|
||||||
|
<label for="currentAnnotation.showOkEvents" class="cr1">Show OK events <tip>Show events, generated when trigger release to OK state</tip></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
"username": "guest",
|
"username": "guest",
|
||||||
"password": "",
|
"password": "",
|
||||||
|
|
||||||
|
"trends": true,
|
||||||
|
"trendsFrom": "7d",
|
||||||
|
|
||||||
"limitmetrics": 50,
|
"limitmetrics": 50,
|
||||||
|
|
||||||
"metrics": true,
|
"metrics": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user