Added support for logging packet loss and min/max/avg response times on fping

This commit is contained in:
laf
2015-06-22 21:55:31 +01:00
parent db4a5de847
commit eee2ae5be1
10 changed files with 268 additions and 15 deletions

View File

@@ -58,5 +58,13 @@ if ($options['f'] === 'perf_times') {
if ($options['f'] === 'callback') {
require_once "callback.php";
}
if ($options['f'] === 'device_perf') {
if (is_numeric($config['device_perf_purge'])) {
if (dbDelete('device_perf', "timestamp < UNIX_TIMESTAMP(DATE_SUB(NOW(),INTERVAL ? DAY))", array($config['device_perf_purge'])) ) {
echo 'Device performance times cleared for entries over ' . $config['device_perf_purge'] . " days\n";
}
}
}
?>

View File

@@ -12,3 +12,4 @@ php daily.php -f eventlog
php daily.php -f authlog
php daily.php -f perf_times
php daily.php -f callback
php daily.php -f device_perf

View File

@@ -502,3 +502,19 @@ Entity: `%macros.sensor`
Description: Only select sensors that aren't ignored.
Source: `(%sensors.sensor_alert = 1)`
## <a name="macros-packetloss">Packet Loss</a> (Boolean)
Entity: `(%macros.packet_loss_5m)`
Description: Packet loss % value for the device within the last 5 minutes.
Example: `%macros.packet_loss_5m` > 50
Entity: `(%macros.packet_loss_15m)`
Description: Packet loss % value for the device within the last 15 minutes.
Example: `%macros.packet_loss_15m` > 50

View File

@@ -404,6 +404,7 @@ $config['syslog_purge'] = 30;
$config['eventlog_purge'] = 30;
$config['authlog_purge'] = 30;
$config['perf_times_purge'] = 30;
$config['device_perf_purge'] = 30;
```
This option will ensure data within LibreNMS over 1 month old is automatically purged. You can alter these individually,
values are in days.

View File

@@ -382,6 +382,13 @@ if (device_permitted($vars['device']) || $check_device == $vars['device'])
</li>');
}
echo('<li class="' . $select['performance'] . '">
<a href="'.generate_device_url($device, array('tab' => 'performance')).'">
<img src="images/16/chart_line.png" align="absmiddle" border="0" /> Performance
</a>
</li>');
echo ('<li style="float: right;"><a href="https://' . $device['hostname'] . '"><img src="images/16/http.png" alt="https" title="Launch browser to https://' . $device['hostname'] . '" border="0" width="16" height="16" target="_blank"></a></li>
<li style="float: right;"><a href="ssh://' . $device['hostname'] . '"><img src="images/16/ssh.png" alt="ssh" title="SSH to ' . $device['hostname'] . '" border="0" width="16" height="16"></a></li>
<li style="float: right;"><a href="telnet://' . $device['hostname'] . '"><img src="images/16/telnet.png" alt="telnet" title="Telnet to ' . $device['hostname'] . '" border="0" width="16" height="16"></a></li>');

View File

@@ -0,0 +1,158 @@
<?php
/*
* LibreNMS
*
* Copyright (c) 2015 Søren Friis Rosiak <sorenrosiak@gmail.com>
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. Please see LICENSE.txt at the top level of
* the source code distribution for details.
* Copyright (c) 2014 Neil Lathwood <https://github.com/laf/ http://www.lathwood.co.uk/fa>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. Please see LICENSE.txt at the top level of
* the source code distribution for details.
*/
if(!isset($vars['section'])) { $vars['section'] = "performance"; }
if (is_admin() === true || is_read() === true) {
$query = "SELECT DATE_FORMAT(timestamp, '".$config['alert_graph_date_format']."') Date, xmt,rcv,loss,min,max,avg FROM `device_perf` WHERE `device_id` = ?";
$param = array($device['device_id']);
} else {
$query = "SELECT DATE_FORMAT(timestamp, '".$config['alert_graph_date_format']."') Date, xmt,rcv,loss,min,max,avg FROM `device_perf`,`devices_perms` WHERE `device_id` = ? AND alert_log.device_id = devices_perms.device_id AND devices_perms.user_id = " . $_SESSION['user_id'];
$param = array($device['device_id']);
}
?>
<script src="js/vis.min.js"></script>
<div id="visualization"></div>
<script type="text/javascript">
var container = document.getElementById('visualization');
<?php
$groups = array();
$max_val = 0;
foreach(dbFetchRows($query, $param) as $return_value) {
$date = $return_value['Date'];
$loss = $return_value['loss'];
$min = $return_value['min'];
$max = $return_value['max'];
$avg = $return_value['avg'];
if ($max > $max_val) {
$max_val = $max;
}
$data[] = array('x' => $date,'y' => $loss,'group' => 0);
$data[] = array('x' => $date,'y' => $min,'group' => 1);
$data[] = array('x' => $date,'y' => $max,'group' => 2);
$data[] = array('x' => $date,'y' => $avg,'group' => 3);
}
$graph_data = _json_encode($data);
?>
var names = ['Loss','Min latency','Max latency','Avg latency'];
var groups = new vis.DataSet();
groups.add({
id: 0,
content: names[0],
options: {
drawPoints: {
style: 'circle'
},
shaded: {
orientation: 'bottom'
}
}
});
groups.add({
id: 1,
content: names[1],
options: {
yAxisOrientation: 'right',
drawPoints: {
style: 'circle'
},
shaded: {
orientation: 'bottom'
}
}
});
groups.add({
id: 2,
content: names[2],
options: {
yAxisOrientation: 'right',
drawPoints: {
style: 'circle'
},
shaded: {
orientation: 'bottom'
}
}
});
groups.add({
id: 3,
content: names[3],
options: {
yAxisOrientation: 'right',
drawPoints: {
style: 'circle'
},
shaded: {
orientation: 'bottom'
}
}
});
<?php
?>
var items =
<?php
echo $graph_data; ?>
;
var dataset = new vis.DataSet(items);
var options = {
barChart: {width:50, align:'right',handleOverlap:'sideBySide'}, // align: left, center, right
drawPoints: false,
legend: {left:{position:"bottom-left"}},
dataAxis: {
icons:true,
showMajorLabels: true,
showMinorLabels: true,
customRange: {
left: {
min: 0, max: 100
},
right: {
min: 0, max: <?php echo $max_val; ?>
}
}
},
zoomMin: 86400, //24hrs
zoomMax: <?php
$first_date = reset($data);
$last_date = end($data);
$milisec_diff = abs(strtotime($first_date[x]) - strtotime($last_date[x])) * 1000;
echo $milisec_diff;
?>,
orientation:'top'
};
var graph2d = new vis.Graph2d(container, items, groups, options);
</script>

View File

@@ -43,6 +43,7 @@ $config['rrdtool'] = "/usr/bin/rrdtool";
$config['fping'] = "/usr/bin/fping";
$config['fping_options']['retries'] = 3;
$config['fping_options']['timeout'] = 500;
$config['fping_options']['count'] = 3;
$config['fping6'] = "/usr/bin/fping6";
$config['snmpwalk'] = "/usr/bin/snmpwalk";
$config['snmpget'] = "/usr/bin/snmpget";
@@ -581,6 +582,7 @@ $config['syslog_purge'] = 30; # Number in days
$config['eventlog_purge'] = 30; # Number in days of how long to keep eventlog entries for.
$config['authlog_purge'] = 30; # Number in days of how long to keep authlog entries for.
$config['perf_times_purge'] = 30; # Number in days of how long to keep performace pooling stats entries for.
$config['device_perf_purge'] = 30; // Number in days of how long to keep device performance data for.
# Date format for PHP date()s
$config['dateformat']['long'] = "r"; # RFC2822 style

View File

@@ -495,25 +495,21 @@ function isPingable($hostname,$device_id = FALSE)
if(is_numeric($config['fping_options']['timeout']) || $config['fping_options']['timeout'] > 1) {
$fping_params .= ' -t ' . $config['fping_options']['timeout'];
}
$status = shell_exec($config['fping'] . "$fping_params -e $hostname 2>/dev/null");
if(is_numeric($config['fping_options']['count']) || $config['fping_options']['count'] > 0) {
$fping_params .= ' -c ' . $config['fping_options']['count'];
}
//$status = shell_exec($config['fping'] . "$fping_params -e $hostname 2>/dev/null");
$response = array();
if (strstr($status, "alive"))
{
$response['result'] = TRUE;
} else {
$status = shell_exec($config['fping6'] . "$fping_params -e $hostname 2>/dev/null");
if (strstr($status, "alive"))
{
$response['result'] = TRUE;
} else {
$status = fping($hostname,$fping_params);
if ($status['loss'] < 0 || $status['loss'] == 100) {
$response['result'] = FALSE;
}
} else {
$response['result'] = TRUE;
}
if(is_numeric($device_id) && !empty($device_id))
{
preg_match('/(\d+\.*\d*) (ms)/', $status, $time);
$response['last_ping_timetaken'] = $time[1];
if (is_numeric($status['avg'])) {
$response['last_ping_timetaken'] = $status['avg'];
}
$response['db'] = $status;
return($response);
}
@@ -1269,3 +1265,55 @@ function ip_exists($ip) {
}
return true;
}
function fping($host,$params) {
global $config;
// $handle = popen($config['fping'] . ' -e -q ' .$params . ' ' .$host.' 2>&1', 'r');
// sleep(0.2);
// $read = fread($handle, 8192);
// pclose($handle);
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$process = proc_open($config['fping'] . ' -e -q ' .$params . ' ' .$host.' 2>&1', $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], $in);
/* fwrite writes to stdin, 'cat' will immediately write the data from stdin
* to stdout and blocks, when the stdout buffer is full. Then it will not
* continue reading from stdin and php will block here.
*/
fclose($pipes[0]);
while (!feof($pipes[1])) {
$read .= fgets($pipes[1], 1024);
}
fclose($pipes[1]);
$return_value = proc_close($process);
}
system("echo 'YEAH $read END\n' >> /tmp/testing");
system("echo '". $config['fping'] ." -e -q $params $host' >> /tmp/testing");
preg_match('/[0-9]+\/[0-9]+\/[0-9]+%/', $read, $loss_tmp);
preg_match('/[0-9\.]+\/[0-9\.]+\/[0-9\.]*$/', $read, $latency);
$loss = preg_replace("/%/","",$loss_tmp[0]);
list($xmt,$rcv,$loss) = preg_split("/\//", $loss);
list($min,$max,$avg) = preg_split("/\//", $latency[0]);
if ($loss < 0) {
$xmt = 1;
$rcv = 1;
$loss = 100;
}
$response = array('xmt'=>$xmt,'rcv'=>$rcv,'loss'=>$loss,'min'=>$min,'max'=>$max,'avg'=>$avg);
return $response;
}

View File

@@ -132,6 +132,15 @@ function poll_device($device, $options)
if (!is_dir($host_rrd)) { mkdir($host_rrd); echo("Created directory : $host_rrd\n"); }
$ping_response = isPingable($device['hostname'],$device['device_id']);
$device_perf = $ping_response['db'];
$device_perf['device_id'] = $device['device_id'];
$device_perf['timestamp'] = array('NOW()');
if (is_array($device_perf)) {
dbInsert($device_perf, 'device_perf');
}
$device['pingable'] = $ping_response['result'];
$ping_time = $ping_response['last_ping_timetaken'];
$response = array();

3
sql-schema/056.sql Normal file
View File

@@ -0,0 +1,3 @@
CREATE TABLE IF NOT EXISTS `device_perf` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `timestamp` datetime NOT NULL, `xmt` float NOT NULL, `rcv` float NOT NULL, `loss` float NOT NULL, `min` float NOT NULL, `max` float NOT NULL, `avg` float NOT NULL, KEY `id` (`id`,`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_15m','(%macros.past_15m && %device_perf.loss)','(%macros.past_15m && %device_perf.loss)','Packet loss over the last 15 minutes','alerting',0,'macros',0,1,0);
insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_5m','(%macros.past_5m && %device_perf.loss)','(%macros.past_5m && %device_perf.loss)','Packet loss over the last 5 minutes','alerting',0,'macros',0,1,0);