diff --git a/LibreNMS/Config.php b/LibreNMS/Config.php
index e461369aaf..e10be7eb3e 100644
--- a/LibreNMS/Config.php
+++ b/LibreNMS/Config.php
@@ -454,7 +454,7 @@ class Config
self::deprecatedVariable('oxidized.group', 'oxidized.maps.group');
// make sure we have full path to binaries in case PATH isn't set
- foreach (array('fping', 'fping6', 'snmpgetnext', 'rrdtool') as $bin) {
+ foreach (array('fping', 'fping6', 'snmpgetnext', 'rrdtool', 'traceroute', 'traceroute6') as $bin) {
if (!is_executable(self::get($bin))) {
self::set($bin, self::locateBinary($bin), $persist, $bin, "Path to $bin", 'external', 'paths');
}
diff --git a/doc/Alerting/Templates.md b/doc/Alerting/Templates.md
index dd022f936e..92f66eaa2e 100644
--- a/doc/Alerting/Templates.md
+++ b/doc/Alerting/Templates.md
@@ -50,6 +50,9 @@ Placeholders are special variables that if used within the template will be repl
- ping min (if icmp enabled): `$alert->ping_min`
- ping max (if icmp enabled): `$alert->ping_max`
- ping avg (if icmp enabled): `$alert->ping_avg`
+- debug (array) If `$config['debug']['run_trace] = true;` is set then this will contain:
+ - traceroute (if enabled you will receive traceroute output): `$alert->debug['traceroute']`
+ - output (if the traceroute fails this will contain why): `$alert->debug['output']`
- Title for the Alert: `$alert->title`
- Time Elapsed, Only available on recovery (`$alert->state == 0`): `$alert->elapsed`
- Rule Builder (the actual rule) (use `{!! $alert->builder !!}`): `$alert->builder`
@@ -108,7 +111,7 @@ More info: https://laravel.com/docs/5.4/blade#extending-a-layout
## Examples
-Default Template:
+#### Default Template:
```text
{{ $alert->title }}
Severity: {{ $alert->severity }}
@@ -126,7 +129,7 @@ Alert sent to:
{{ $value }} <{{ $key }}>
@endforeach
```
-Ports Utilization Template:
+#### Ports Utilization Template:
```text
{{ $alert->title }}
Device Name: {{ $alert->hostname }}
@@ -143,7 +146,7 @@ Outbound Utilization: {{ (($value['ifOutOctets_rate']*8)/$value['ifSpeed'])*100
@endforeach
```
-Storage:
+#### Storage:
```text
{{ $alert->title }}
@@ -165,7 +168,7 @@ Percent Utilized: {{ $value['storage_perc'] }}
@endforeach
```
-Temperature Sensors:
+#### Temperature Sensors:
```text
{{ $alert->title }}
@@ -191,7 +194,7 @@ High Temperature Limit: {{ $value['sensor_limit'] }} °C
@endif
```
-Value Sensors:
+#### Value Sensors:
```text
{{ $alert->title }}
@@ -217,7 +220,7 @@ Limit: {{ $value['sensor_limit'] }}
@endif
```
-Memory Alert:
+#### Memory Alert:
```text
{{ $alert->title }}
@@ -237,7 +240,9 @@ Percent Utilized: {{ $value['mempool_perc'] }}
@endforeach
```
+### Advanced options
+#### Conditional formatting
Conditional formatting example, will display a link to the host in email or just the hostname in any other transport:
```text
@if ($alert->transport == mail){{ $alert->hostname }}
@@ -246,6 +251,15 @@ Conditional formatting example, will display a link to the host in email or just
@endif
```
+#### Traceroute debugs
+```text
+@if ($alert->status == 0)
+ @if ($alert->status == icmp)
+ {{ $alert->debug['traceroute'] }}
+ @endif
+@endif
+```
+
## Examples HTML
Note: To use HTML emails you must set HTML email to Yes in the WebUI under Global Settings > Alerting Settings > Email transport > Use HTML emails
@@ -277,7 +291,7 @@ Service Alert:
```
-Processor Alert with Graph:
+#### Processor Alert with Graph:
```
{{ $alert->title }}
Severity: {{ $alert->severity }}
diff --git a/doc/Support/Configuration.md b/doc/Support/Configuration.md
index 704723b108..67d7efa950 100644
--- a/doc/Support/Configuration.md
+++ b/doc/Support/Configuration.md
@@ -100,6 +100,15 @@ $config['icmp_check'] = false;
If you would like to do this on a per device basis then you can do so under Device -> Edit -> Misc -> Disable ICMP Test? On
+#### traceroute
+LibreNMS uses traceroute / traceroute6 to record debug information when a device is down due to icmp AND you have `$config['debug']['run_trace] = true;`
+set.
+
+```php
+$config['traceroute'] = '/usr/bin/traceroute';
+$config['traceroute6'] = '/usr/bin/traceroute6';
+```
+
#### SNMP
```php
diff --git a/html/includes/dev-overview-data.inc.php b/html/includes/dev-overview-data.inc.php
index d9bfcee193..822d9b0dc7 100644
--- a/html/includes/dev-overview-data.inc.php
+++ b/html/includes/dev-overview-data.inc.php
@@ -1,5 +1,6 @@
$uptime_text |
- ".$uptime." |
+ $uptime |
";
}
echo '
-
';
+
+$perf_info = DevicePerf::where('device_id', $device['device_id'])->latest('timestamp')->first();
+$perf_debug = json_decode($perf_info['debug'], true);
+if ($perf_debug['traceroute']) {
+ echo "
+
+
+
+
Traceroute ({$perf_info['timestamp']})
+
+
+
{$perf_debug['traceroute']}
+
+
+
+
";
+}
+
+echo '';
diff --git a/includes/alerts.inc.php b/includes/alerts.inc.php
index 8532dea161..572072d456 100644
--- a/includes/alerts.inc.php
+++ b/includes/alerts.inc.php
@@ -22,6 +22,7 @@
* @subpackage Alerts
*/
+use App\Models\DevicePerf;
use LibreNMS\Alert\Template;
use LibreNMS\Alert\AlertData;
use LibreNMS\Alerting\QueryBuilderParser;
@@ -414,36 +415,37 @@ function DescribeAlert($alert)
{
$obj = array();
$i = 0;
- $device = dbFetchRow('SELECT hostname, sysName, sysDescr, sysContact, os, type, ip, hardware, version, location, purpose, notes, uptime FROM devices WHERE device_id = ?', array($alert['device_id']));
+ $device = dbFetchRow('SELECT hostname, sysName, sysDescr, sysContact, os, type, ip, hardware, version, location, purpose, notes, uptime, status, status_reason FROM devices WHERE device_id = ?', array($alert['device_id']));
$attribs = get_dev_attribs($alert['device_id']);
- if (can_ping_device($attribs)) {
- $ping_stats = dbFetchRow('SELECT `timestamp`, `loss`, `min`, `max`, `avg` FROM `device_perf` WHERE `device_id` = ? ORDER BY `timestamp` LIMIT 1', [$alert['device_id']]);
- }
- $obj['hostname'] = $device['hostname'];
- $obj['sysName'] = $device['sysName'];
- $obj['sysDescr'] = $device['sysDescr'];
- $obj['sysContact'] = $device['sysContact'];
- $obj['os'] = $device['os'];
- $obj['type'] = $device['type'];
- $obj['ip'] = inet6_ntop($device['ip']);
- $obj['hardware'] = $device['hardware'];
- $obj['version'] = $device['version'];
- $obj['location'] = $device['location'];
- $obj['uptime'] = $device['uptime'];
- $obj['uptime_short'] = formatUptime($device['uptime'], 'short');
- $obj['uptime_long'] = formatUptime($device['uptime']);
- $obj['description'] = $device['purpose'];
- $obj['notes'] = $device['notes'];
- $obj['alert_notes'] = $alert['note'];
- $obj['device_id'] = $alert['device_id'];
- $obj['rule_id'] = $alert['rule_id'];
+ $obj['hostname'] = $device['hostname'];
+ $obj['sysName'] = $device['sysName'];
+ $obj['sysDescr'] = $device['sysDescr'];
+ $obj['sysContact'] = $device['sysContact'];
+ $obj['os'] = $device['os'];
+ $obj['type'] = $device['type'];
+ $obj['ip'] = inet6_ntop($device['ip']);
+ $obj['hardware'] = $device['hardware'];
+ $obj['version'] = $device['version'];
+ $obj['location'] = $device['location'];
+ $obj['uptime'] = $device['uptime'];
+ $obj['uptime_short'] = formatUptime($device['uptime'], 'short');
+ $obj['uptime_long'] = formatUptime($device['uptime']);
+ $obj['description'] = $device['purpose'];
+ $obj['notes'] = $device['notes'];
+ $obj['alert_notes'] = $alert['note'];
+ $obj['device_id'] = $alert['device_id'];
+ $obj['rule_id'] = $alert['rule_id'];
+ $obj['status'] = $device['status'];
+ $obj['status_reason'] = $device['status_reason'];
if (can_ping_device($attribs)) {
- $obj['ping_timestamp'] = $ping_stats['template'];
- $obj['ping_loss'] = $ping_stats['loss'];
- $obj['ping_min'] = $ping_stats['min'];
- $obj['ping_max'] = $ping_stats['max'];
- $obj['ping_avg'] = $ping_stats['avg'];
+ $ping_stats = DevicePerf::where('device_id', $alert['device_id'])->latest('timestamp')->first();
+ $obj['ping_timestamp'] = $ping_stats->template;
+ $obj['ping_loss'] = $ping_stats->loss;
+ $obj['ping_min'] = $ping_stats->min;
+ $obj['ping_max'] = $ping_stats->max;
+ $obj['ping_avg'] = $ping_stats->avg;
+ $obj['debug'] = json_decode($ping_stats->debug, true);
}
$extra = $alert['details'];
diff --git a/includes/functions.php b/includes/functions.php
index db24f52186..da5819a0c1 100644
--- a/includes/functions.php
+++ b/includes/functions.php
@@ -2208,6 +2208,19 @@ function recordSnmpStatistic($stat, $start_time)
return $runtime;
}
+function runTraceroute($device)
+{
+ $address_family = snmpTransportToAddressFamily($device['transport']);
+ $trace_name = $address_family == 'ipv6' ? 'traceroute6' : 'traceroute';
+ $trace_path = Config::get($trace_name, $trace_name);
+ $process = new Process([$trace_path, '-q', '1', '-w', '1', $device['hostname']]);
+ $process->run();
+ if ($process->isSuccessful()) {
+ return ['traceroute' => $process->getOutput()];
+ }
+ return ['output' => $process->getErrorOutput()];
+}
+
/**
* @param $device
* @param bool $record_perf
@@ -2221,7 +2234,12 @@ function device_is_up($device, $record_perf = false)
$device_perf['device_id'] = $device['device_id'];
$device_perf['timestamp'] = array('NOW()');
- if ($record_perf === true && can_ping_device($device['attribs']) === true) {
+ if ($record_perf === true && can_ping_device($device['attribs'])) {
+ $trace_debug = [];
+ if ($ping_response['result'] === false && Config::get('debug.run_trace', false)) {
+ $trace_debug = runTraceroute($device);
+ }
+ $device_perf['debug'] = json_encode($trace_debug);
dbInsert($device_perf, 'device_perf');
}
$response = array();
diff --git a/misc/db_schema.yaml b/misc/db_schema.yaml
index 2f319f0faa..6062927c61 100644
--- a/misc/db_schema.yaml
+++ b/misc/db_schema.yaml
@@ -555,6 +555,7 @@ device_perf:
- { Field: min, Type: 'double(8,2)', 'Null': false, Extra: '' }
- { Field: max, Type: 'double(8,2)', 'Null': false, Extra: '' }
- { Field: avg, Type: 'double(8,2)', 'Null': false, Extra: '' }
+ - { Field: debug, Type: text, 'Null': true, Extra: '' }
Indexes:
PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE }
device_id: { Name: device_id, Columns: [device_id], Unique: false, Type: BTREE }
diff --git a/sql-schema/271.sql b/sql-schema/271.sql
new file mode 100644
index 0000000000..e41946a9f4
--- /dev/null
+++ b/sql-schema/271.sql
@@ -0,0 +1 @@
+ALTER TABLE `device_perf` ADD `debug` TEXT NULL;