mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Added support for logging packet loss and min/max/avg response times on fping
This commit is contained in:
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
1
daily.sh
1
daily.sh
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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>');
|
||||
|
158
html/pages/device/performance.inc.php
Normal file
158
html/pages/device/performance.inc.php
Normal 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>
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
3
sql-schema/056.sql
Normal 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);
|
Reference in New Issue
Block a user