mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
add support for Sagan (#14070)
* add sagan instance fetch function * add sagan discovery * add sagan poller * add sagan graphs * add graph sources * add sagan to apps page * remove alert * more app graph work * polling fix * re-order keys and add alert key * correct field key usage * add alert and fix a missing unit * more unit fixes * add alert status * add alert rules for sagan * fix a missing : after S while I am here in the json stat tool helper... also add tests * now add the tests * add docs * point php-cs-fixer at two files * remove-unneeded sagan instance fetch function * convert to use app_data * style fix * apply bennet-esyoil's suggestions here as well * update for the new app model * convert poller to the new method * convert the sagan device app page * convert sagan * doc cleanup
This commit is contained in:
committed by
GitHub
parent
1d1b2b1c8b
commit
b827e2bbbd
@@ -2183,6 +2183,74 @@ extend supervisord /etc/snmp/supervisord.py
|
||||
systemctl restart snmpd
|
||||
```
|
||||
|
||||
## Sagan
|
||||
|
||||
For metrics the stats are migrated as below from the stats JSON.
|
||||
|
||||
`f_drop_percent` and `drop_percent` are computed based on the found data.
|
||||
|
||||
| Instance Key | Stats JSON Key |
|
||||
|--------------------|------------------------------------|
|
||||
| uptime | .stats.uptime |
|
||||
| total | .stats.captured.total |
|
||||
| drop | .stats.captured.drop |
|
||||
| ignore | .stats.captured.ignore |
|
||||
| threshold | .stats.captured.theshold |
|
||||
| after | .stats.captured.after |
|
||||
| match | .stats.captured.match |
|
||||
| bytes | .stats.captured.bytes_total |
|
||||
| bytes_ignored | .stats.captured.bytes_ignored |
|
||||
| max_bytes_log_line | .stats.captured.max_bytes_log_line |
|
||||
| eps | .stats.captured.eps |
|
||||
| f_total | .stats.flow.total |
|
||||
| f_dropped | .stats.flow.dropped |
|
||||
|
||||
Those keys are appended with the name of the instance running with `_`
|
||||
between the instance name and instance metric key. So `uptime` for
|
||||
`ids` would be `ids_uptime`.
|
||||
|
||||
The default is named 'ids' unless otherwise specified via the extend.
|
||||
|
||||
There is a special instance name of `.total` which is the total of all
|
||||
the instances. So if you want the total eps, the metric would be
|
||||
`.total_eps`. Also worth noting that the alert value is the highest
|
||||
one found among all the instances.
|
||||
|
||||
### SNMP Extend
|
||||
|
||||
1. Install the extend.
|
||||
```
|
||||
cpanm Sagan::Monitoring
|
||||
```
|
||||
|
||||
2. Setup cron. Below is a example.
|
||||
```
|
||||
*/5 * * * * /usr/local/bin/sagan_stat_check > /dev/null
|
||||
```
|
||||
|
||||
3. Configure snmpd.conf
|
||||
```
|
||||
extend sagan-stats /usr/bin/env PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin sagan_stat_check -c
|
||||
```
|
||||
|
||||
4. Restart snmpd on your system.
|
||||
|
||||
You will want to make sure that sagan is setup to with the values set
|
||||
below for stats-json processor, for a single instance setup..
|
||||
|
||||
```
|
||||
enabled: yes
|
||||
time: 300
|
||||
subtract_old_values: true
|
||||
filename: "$LOG_PATH/stats.json"
|
||||
```
|
||||
|
||||
Any configuration of sagan_stat_check should be done in the cron
|
||||
setup. If the default does not work, check the docs for it at
|
||||
[MetaCPAN for
|
||||
sagan_stat_check](https://metacpan.org/dist/Sagan-Monitoring/view/bin/sagan_stat_check)
|
||||
|
||||
|
||||
## Suricata
|
||||
|
||||
### SNMP Extend
|
||||
|
||||
@@ -47,6 +47,7 @@ if ($results) {
|
||||
$applications['phpfpmsp'] = 'php-fpm';
|
||||
$applications['postfixdetailed'] = 'postfix';
|
||||
$applications['suricata-stats'] = 'suricata';
|
||||
$applications['sagan-stats'] = 'sagan';
|
||||
}
|
||||
|
||||
d_echo(PHP_EOL . 'Available: ' . implode(', ', array_keys($applications)) . PHP_EOL);
|
||||
|
||||
28
includes/html/graphs/application/sagan_after.inc.php
Normal file
28
includes/html/graphs/application/sagan_after.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'After';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'After',
|
||||
'ds' => 'after',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_alert.inc.php
Normal file
28
includes/html/graphs/application/sagan_alert.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Status';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Alert',
|
||||
'ds' => 'alert',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_bytes.inc.php
Normal file
28
includes/html/graphs/application/sagan_bytes.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Bytes';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Bytes',
|
||||
'ds' => 'bytes',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_bytes_ignored.inc.php
Normal file
28
includes/html/graphs/application/sagan_bytes_ignored.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Bytes';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Bytes Ignores',
|
||||
'ds' => 'bytes_ignored',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_drop.inc.php
Normal file
28
includes/html/graphs/application/sagan_drop.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Drop';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Drop',
|
||||
'ds' => 'drop',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_drop_percent.inc.php
Normal file
28
includes/html/graphs/application/sagan_drop_percent.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Percent';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Drop%',
|
||||
'ds' => 'drop_percent',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_eps.inc.php
Normal file
28
includes/html/graphs/application/sagan_eps.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Events Per Second';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'EPS',
|
||||
'ds' => 'eps',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Percent';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Flow Drop%',
|
||||
'ds' => 'f_drop_percent',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_f_dropped.inc.php
Normal file
28
includes/html/graphs/application/sagan_f_dropped.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Flows Dropped';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Flows Dropped',
|
||||
'ds' => 'f_dropped',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_f_total.inc.php
Normal file
28
includes/html/graphs/application/sagan_f_total.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Flows';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Flows',
|
||||
'ds' => 'f_total',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_ignore.inc.php
Normal file
28
includes/html/graphs/application/sagan_ignore.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Ignored';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Ignored',
|
||||
'ds' => 'ignore',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_match.inc.php
Normal file
28
includes/html/graphs/application/sagan_match.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Matched';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Matched',
|
||||
'ds' => 'match',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Bytes';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Max Log Line',
|
||||
'ds' => 'max_bytes_log_line',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_threshold.inc.php
Normal file
28
includes/html/graphs/application/sagan_threshold.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Threshold';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Threshold',
|
||||
'ds' => 'threshold',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_total.inc.php
Normal file
28
includes/html/graphs/application/sagan_total.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Total';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Total',
|
||||
'ds' => 'total',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
28
includes/html/graphs/application/sagan_uptime.inc.php
Normal file
28
includes/html/graphs/application/sagan_uptime.inc.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$name = 'sagan';
|
||||
$unit_text = 'Seconds';
|
||||
$colours = 'psychedelic';
|
||||
$dostack = 0;
|
||||
$printtotal = 0;
|
||||
$addarea = 0;
|
||||
$transparency = 15;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id, $vars['sinstance']]);
|
||||
} else {
|
||||
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app->app_id]);
|
||||
}
|
||||
|
||||
$rrd_list = [];
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => 'Uptime',
|
||||
'ds' => 'uptime',
|
||||
];
|
||||
} else {
|
||||
d_echo('RRD "' . $rrd_filename . '" not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line.inc.php';
|
||||
@@ -388,6 +388,24 @@ $graphs['chronyd'] = [
|
||||
'frequency',
|
||||
'root',
|
||||
];
|
||||
$graphs['sagan'] = [
|
||||
'after',
|
||||
'bytes_ignored',
|
||||
'bytes',
|
||||
'drop_percent',
|
||||
'drop',
|
||||
'eps',
|
||||
'f_drop_percent',
|
||||
'f_dropped',
|
||||
'f_total',
|
||||
'ignore',
|
||||
'match',
|
||||
'max_bytes_log_line',
|
||||
'threshold',
|
||||
'total',
|
||||
'uptime',
|
||||
'alert',
|
||||
];
|
||||
|
||||
echo '<div class="panel panel-default">';
|
||||
echo '<div class="panel-heading">';
|
||||
|
||||
70
includes/html/pages/device/apps/sagan.inc.php
Normal file
70
includes/html/pages/device/apps/sagan.inc.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
$link_array = [
|
||||
'page' => 'device',
|
||||
'device' => $device['device_id'],
|
||||
'tab' => 'apps',
|
||||
'app' => 'sagan',
|
||||
];
|
||||
|
||||
print_optionbar_start();
|
||||
|
||||
echo generate_link('Totals', $link_array);
|
||||
|
||||
$sagan_instances = $app->data['instances'] ?? [];
|
||||
sort($sagan_instances);
|
||||
foreach ($sagan_instances as $index => $sinstance) {
|
||||
$label = $vars['sinstance'] == $sinstance
|
||||
? '<span class="pagemenu-selected">' . $sinstance . '</span>'
|
||||
: $sinstance;
|
||||
|
||||
echo generate_link($label, $link_array, ['sinstance' => $sinstance]);
|
||||
|
||||
if ($index < (count($sagan_instances) - 1)) {
|
||||
echo ', ';
|
||||
}
|
||||
}
|
||||
|
||||
print_optionbar_end();
|
||||
|
||||
$graphs = [
|
||||
'sagan_bytes'=>'Bytes',
|
||||
'sagan_eps'=>'Events Per Second',
|
||||
'sagan_total'=>'Recieved Log Entries',
|
||||
'sagan_drop'=>'Drop',
|
||||
'sagan_drop_percent'=>'Drop Percent',
|
||||
'sagan_f_total'=>'Flows Total',
|
||||
'sagan_f_dropped'=>'Flows Dropped',
|
||||
'sagan_f_drop_percent'=>'Flows Dropped Percent',
|
||||
'sagan_ignore'=>'Ignore',
|
||||
'sagan_bytes_ignored'=>'Bytes Ignored',
|
||||
'sagan_match'=>'Match',
|
||||
'sagan_max_bytes_log_line'=>'Max Bytes Log Line',
|
||||
'sagan_threshold'=>'Threshold',
|
||||
'sagan_uptime'=>'Uptime',
|
||||
'sagan_alert'=>'Alert: 0=OK, 1=WARNING, 2=CRITICAL, 3+UNKNOWN',
|
||||
];
|
||||
|
||||
foreach ($graphs as $key => $text) {
|
||||
$graph_type = $key;
|
||||
$graph_array['height'] = '100';
|
||||
$graph_array['width'] = '215';
|
||||
$graph_array['to'] = \LibreNMS\Config::get('time.now');
|
||||
$graph_array['id'] = $app['app_id'];
|
||||
$graph_array['type'] = 'application_' . $key;
|
||||
|
||||
if (isset($vars['sinstance'])) {
|
||||
$graph_array['sinstance'] = $vars['sinstance'];
|
||||
}
|
||||
|
||||
echo '<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">' . $text . '</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">';
|
||||
include 'includes/html/print-graphrow.inc.php';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
101
includes/polling/applications/sagan.inc.php
Normal file
101
includes/polling/applications/sagan.inc.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
use LibreNMS\Exceptions\JsonAppException;
|
||||
use LibreNMS\RRD\RrdDefinition;
|
||||
|
||||
$name = 'sagan';
|
||||
|
||||
if (! is_array($app_data['instances'])) {
|
||||
$app_data['instances'] = [];
|
||||
}
|
||||
|
||||
try {
|
||||
$sagan = json_app_get($device, 'sagan-stats');
|
||||
} catch (JsonAppException $e) {
|
||||
echo PHP_EOL . $name . ':' . $e->getCode() . ':' . $e->getMessage() . PHP_EOL;
|
||||
update_application($app, $e->getCode() . ':' . $e->getMessage(), []); // Set empty metrics and error message
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// grab the alert here as it is the global one
|
||||
$metrics = ['alert'=>$sagan['alert']];
|
||||
|
||||
$rrd_def = RrdDefinition::make()
|
||||
->addDataset('after', 'GAUGE', 0)
|
||||
->addDataset('alert', 'GAUGE', 0)
|
||||
->addDataset('bytes', 'GAUGE', 0)
|
||||
->addDataset('bytes_ignored', 'GAUGE', 0)
|
||||
->addDataset('drop', 'GAUGE', 0)
|
||||
->addDataset('drop_percent', 'GAUGE', 0)
|
||||
->addDataset('eps', 'GAUGE', 0)
|
||||
->addDataset('f_drop_percent', 'GAUGE', 0)
|
||||
->addDataset('f_dropped', 'GAUGE', 0)
|
||||
->addDataset('f_total', 'GAUGE', 0)
|
||||
->addDataset('ignore', 'GAUGE', 0)
|
||||
->addDataset('match', 'GAUGE', 0)
|
||||
->addDataset('max_bytes_log_line', 'GAUGE', 0)
|
||||
->addDataset('threshold', 'GAUGE', 0)
|
||||
->addDataset('total', 'GAUGE', 0)
|
||||
->addDataset('uptime', 'GAUGE', 0);
|
||||
|
||||
// keys to add to the RRD field
|
||||
$field_keys = [
|
||||
'after',
|
||||
'alert',
|
||||
'bytes',
|
||||
'bytes_ignored',
|
||||
'drop',
|
||||
'drop_percent',
|
||||
'eps',
|
||||
'f_drop_percent',
|
||||
'f_dropped',
|
||||
'f_total',
|
||||
'ignore',
|
||||
'match',
|
||||
'max_bytes_log_line',
|
||||
'threshold',
|
||||
'total',
|
||||
'uptime',
|
||||
];
|
||||
|
||||
// process each instance
|
||||
$instances = [];
|
||||
foreach ($sagan['data'] as $instance => $stats) {
|
||||
if ($instance == '.total') {
|
||||
$rrd_name = ['app', $name, $app->app_id];
|
||||
} else {
|
||||
$rrd_name = ['app', $name, $app->app_id, $instance];
|
||||
$instances[] = $instance;
|
||||
}
|
||||
|
||||
$fields = [];
|
||||
foreach ($field_keys as $field_key) {
|
||||
$metrics[$instance . '_' . $field_key] = $stats[$field_key];
|
||||
$fields[$field_key] = $stats[$field_key];
|
||||
}
|
||||
|
||||
$tags = ['name' => $name, 'app_id' => $app->app_id, 'rrd_def' => $rrd_def, 'rrd_name' => $rrd_name];
|
||||
data_update($device, 'app', $tags, $fields);
|
||||
}
|
||||
$old_instances = $app->app['instances'];
|
||||
|
||||
//check for added instances
|
||||
$added_instances = array_values(array_diff($instances, $old_instances));
|
||||
|
||||
//check for removed instances
|
||||
$removed_instances = array_values(array_diff($old_instances, $instances));
|
||||
|
||||
// if we have any instance changes, log it
|
||||
if (sizeof($added_instances) > 0 or sizeof($removed_instances) > 0) {
|
||||
$app->data = ['instances' => $instances];
|
||||
$log_message = 'Sagan Instance Change:';
|
||||
$log_message .= count($added_instances) > 0 ? ' Added ' . json_encode($added_instances) : '';
|
||||
$log_message .= count($removed_instances) > 0 ? ' Removed ' . json_encode($added_instances) : '';
|
||||
log_event($log_message, $device, 'application');
|
||||
}
|
||||
|
||||
//
|
||||
// all done so update the app metrics
|
||||
//
|
||||
update_application($app, 'OK', $metrics);
|
||||
@@ -533,6 +533,41 @@
|
||||
"name": "MySQL Server not responding",
|
||||
"severity":"critical"
|
||||
},
|
||||
{
|
||||
"rule": "applications.app_type = \"sagan\" && application_metrics.metric = \".total_alert\" && application_metrics.value = \"1\"",
|
||||
"name": "Sagan has a WARNING alert",
|
||||
"severity": "warning"
|
||||
},
|
||||
{
|
||||
"rule": "applications.app_type = \"sagan\" && application_metrics.metric = \".total_alert\" && application_metrics.value = \"2\"",
|
||||
"name": "Sagan has a CRITICAL alert",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"rule": "applications.app_type = \"sagan\" && application_metrics.metric = \".total_alert\" && application_metrics.value = \"3\"",
|
||||
"name": "Sagan has a UNKNOWN alert",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"rule": "applications.app_type = \"sagan\" && application_metrics.metric = \".total_f_drop_percent\" && application_metrics.value >= \"1\"",
|
||||
"name": "Sagan Flow Drop Percent >= 1%",
|
||||
"severity": "warning"
|
||||
},
|
||||
{
|
||||
"rule": "applications.app_type = \"sagan\" && application_metrics.metric = \".total_f_drop_percent\" && application_metrics.value >= \"2\"",
|
||||
"name": "Sagan Flow Drop Percent >= 2%",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"rule": "applications.app_type = \"sagan\" && application_metrics.metric = \".total_drop_percent\" && application_metrics.value >= \"1\"",
|
||||
"name": "Sagan Drop Percent >= 1%",
|
||||
"severity": "warning"
|
||||
},
|
||||
{
|
||||
"rule": "applications.app_type = \"sagan\" && application_metrics.metric = \".total_drop_percent\" && application_metrics.value >= \"2\"",
|
||||
"name": "Sagan Drop Percent >= 2%",
|
||||
"severity": "critical"
|
||||
},
|
||||
{
|
||||
"rule": "storage.storage_deleted = 0 AND storage.storage_descr = \"/\" AND storage.storage_perc >= 90 AND storage.storage_perc < 95",
|
||||
"name": "Space on / is >= 90% and < 95% in use",
|
||||
|
||||
@@ -34,7 +34,7 @@ function string_to_oid($string)
|
||||
}//end string_to_oid()
|
||||
|
||||
// Options!
|
||||
$short_opts = 'sktmlhj:a:S';
|
||||
$short_opts = 'S:sktmlhj:a:';
|
||||
$options = getopt($short_opts);
|
||||
|
||||
// print the help
|
||||
|
||||
228
tests/data/linux_sagan-v1.sjon
Normal file
228
tests/data/linux_sagan-v1.sjon
Normal file
@@ -0,0 +1,228 @@
|
||||
{
|
||||
"applications": {
|
||||
"discovery": {
|
||||
"applications": [
|
||||
{
|
||||
"app_type": "sagan",
|
||||
"app_state": "UNKNOWN",
|
||||
"discovered": "1",
|
||||
"app_state_prev": null,
|
||||
"app_status": "",
|
||||
"app_instance": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"poller": {
|
||||
"applications": [
|
||||
{
|
||||
"app_type": "sagan",
|
||||
"app_state": "OK",
|
||||
"discovered": "1",
|
||||
"app_state_prev": "UNKNOWN",
|
||||
"app_status": "",
|
||||
"app_instance": ""
|
||||
}
|
||||
],
|
||||
"application_metrics": [
|
||||
{
|
||||
"metric": ".total_after",
|
||||
"value": 423,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_alert",
|
||||
"value": "0",
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_bytes",
|
||||
"value": 260930,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_bytes_ignored",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_drop",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_drop_percent",
|
||||
"value": "0.00000",
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_eps",
|
||||
"value": 4,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_f_drop_percent",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_f_dropped",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_f_total",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_ignore",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_match",
|
||||
"value": 677,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_max_bytes_log_line",
|
||||
"value": 1202,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_threshold",
|
||||
"value": 425,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_total",
|
||||
"value": 1424,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": ".total_uptime",
|
||||
"value": 3939964,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_after",
|
||||
"value": 423,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_alert",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_alertString",
|
||||
"value": "",
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_bytes",
|
||||
"value": 260930,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_bytes_ignored",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_drop",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_drop_percent",
|
||||
"value": "0.00000",
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_eps",
|
||||
"value": 4,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_f_drop_percent",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_f_dropped",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_f_total",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_ignore",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_match",
|
||||
"value": 677,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_max_bytes_log_line",
|
||||
"value": 1202,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_threshold",
|
||||
"value": 425,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_total",
|
||||
"value": 1424,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
},
|
||||
{
|
||||
"metric": "ids_uptime",
|
||||
"value": 3939964,
|
||||
"value_prev": null,
|
||||
"app_type": "sagan"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
10
tests/snmpsim/linux_sagan-v1.snmprec
Normal file
10
tests/snmpsim/linux_sagan-v1.snmprec
Normal file
@@ -0,0 +1,10 @@
|
||||
1.3.6.1.2.1.1.1.0|4|Linux server 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64
|
||||
1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10
|
||||
1.3.6.1.2.1.1.3.0|67|77550514
|
||||
1.3.6.1.2.1.1.4.0|4|<private>
|
||||
1.3.6.1.2.1.1.5.0|4|<private>
|
||||
1.3.6.1.2.1.1.6.0|4|<private>
|
||||
1.3.6.1.2.1.25.1.1.0|67|77552962
|
||||
1.3.6.1.4.1.8072.1.3.2.2.1.21.6.100.105.115.116.114.111|2|1
|
||||
1.3.6.1.4.1.8072.1.3.2.2.1.21.11.115.97.103.97.110.45.115.116.97.116.115|2|1
|
||||
1.3.6.1.4.1.8072.1.3.2.3.1.2.11.115.97.103.97.110.45.115.116.97.116.115|4x|7b22616c657274223a2230222c22616c657274537472696e67223a22222c2264617461223a7b222e746f74616c223a7b226166746572223a3432332c22616c657274223a2230222c226279746573223a3236303933302c2262797465735f69676e6f726564223a302c2264726f70223a302c2264726f705f70657263656e74223a22302e3030303030222c22657073223a342c22665f64726f705f70657263656e74223a302c22665f64726f70706564223a302c22665f746f74616c223a302c2269676e6f7265223a302c226d61746368223a3637372c226d61785f62797465735f6c6f675f6c696e65223a313230322c227468726573686f6c64223a3432352c22746f74616c223a313432342c22757074696d65223a333933393936347d2c22696473223a7b226166746572223a3432332c22616c657274223a302c22616c657274537472696e67223a22222c226279746573223a3236303933302c2262797465735f69676e6f726564223a302c2264726f70223a302c2264726f705f70657263656e74223a22302e3030303030222c22657073223a342c22665f64726f705f70657263656e74223a302c22665f64726f70706564223a302c22665f746f74616c223a302c2269676e6f7265223a302c226d61746368223a3637372c226d61785f62797465735f6c6f675f6c696e65223a313230322c227468726573686f6c64223a3432352c22746f74616c223a313432342c22757074696d65223a333933393936347d7d2c226572726f72223a2230222c226572726f72537472696e67223a22222c2276657273696f6e223a317d0a
|
||||
Reference in New Issue
Block a user