diff --git a/daily.php b/daily.php index 03176a47d..abb525a0b 100644 --- a/daily.php +++ b/daily.php @@ -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"; + } + } +} + ?> diff --git a/daily.sh b/daily.sh index 4168d7344..91183d6d1 100755 --- a/daily.sh +++ b/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 diff --git a/doc/Extensions/Alerting.md b/doc/Extensions/Alerting.md index 9390e53af..d90bf4ff0 100644 --- a/doc/Extensions/Alerting.md +++ b/doc/Extensions/Alerting.md @@ -502,3 +502,19 @@ Entity: `%macros.sensor` Description: Only select sensors that aren't ignored. Source: `(%sensors.sensor_alert = 1)` + +## Packet Loss (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 + + diff --git a/doc/Support/Configuration.md b/doc/Support/Configuration.md index ae3ee9e19..43d11cffd 100644 --- a/doc/Support/Configuration.md +++ b/doc/Support/Configuration.md @@ -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. diff --git a/html/pages/device.inc.php b/html/pages/device.inc.php index c72daf9bf..ff6a42775 100644 --- a/html/pages/device.inc.php +++ b/html/pages/device.inc.php @@ -382,6 +382,13 @@ if (device_permitted($vars['device']) || $check_device == $vars['device']) '); } + echo('
  • + + Performance + +
  • '); + + echo ('
  • https
  • ssh
  • telnet
  • '); diff --git a/html/pages/device/performance.inc.php b/html/pages/device/performance.inc.php new file mode 100644 index 000000000..1c642daf4 --- /dev/null +++ b/html/pages/device/performance.inc.php @@ -0,0 +1,158 @@ + +* 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 +* +* 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']); +} + +?> + + +
    + + diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index a150c2daa..24b43b99f 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -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 diff --git a/includes/functions.php b/includes/functions.php index 725850897..f158067ca 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -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; +} + diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index c705eccb8..03ec28b0a 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -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(); diff --git a/sql-schema/056.sql b/sql-schema/056.sql new file mode 100644 index 000000000..f8617ab98 --- /dev/null +++ b/sql-schema/056.sql @@ -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);