Add munin monitoring plugin (#892)

* Add munin monitoring plugin

* Ensure stable field ordering for munin
This commit is contained in:
Hamish Coleman 2021-11-05 11:14:47 +00:00 committed by GitHub
parent 0e8de87e38
commit f5e2f3086e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 353 additions and 0 deletions

View File

@ -67,3 +67,32 @@ build process.
It looks at both the VERSION file and the GIT tags and outputs the It looks at both the VERSION file and the GIT tags and outputs the
version number to use. version number to use.
## Monitoring and statistics
### `munin/n2n_`
This is a simple monitoring script that can be used with the munin-node
system to monitor the n2n daemons.
This is a fully autoconfigurable wildcard munin plugin, but to get a quick
sample:
get a list of suggested plugin names:
```
munin/n2n_ suggest
```
Enable some of those names:
```
ln -s /usr/share/munin/plugins/n2n_ /etc/munin/plugins/n2n_supernode_pkts
ln -s /usr/share/munin/plugins/n2n_ /etc/munin/plugins/n2n_supernode_counts
```
Manually test fetching and config:
```
/etc/munin/plugins/n2n_supernode_pkts
/etc/munin/plugins/n2n_supernode_pkts config
```

324
scripts/munin/n2n_ Executable file
View File

@ -0,0 +1,324 @@
#!/usr/bin/env perl
use warnings;
use strict;
#
# Requires
# libjson-perl
#
# Magic Markers
#
#%# family=auto
#%# capabilities=autoconf suggest
package JsonUDP;
use warnings;
use strict;
use IO::Socket::INET;
use JSON;
sub new {
my $class = shift;
my $port = shift || 5644;
my $self = {};
bless($self, $class);
$self->{sock} = IO::Socket::INET->new(
PeerAddr => '127.0.0.1',
PeerPort => $port,
Proto => 'udp',
);
$self->{json} = JSON->new->utf8->relaxed->pretty->canonical;
$self->{tag} = 0;
$self->{debug} = 0;
return $self;
}
sub _tx {
my $self = shift;
my $msgline = shift;
return $self->{sock}->send($msgline);
}
sub _rx {
my $self = shift;
my $tag = shift;
my $db = [];
my $error;
while(1) {
my $jsontxt;
$self->{sock}->recv($jsontxt,1024);
if ($self->{debug}) {
print($jsontxt);
}
my $msg = $self->{json}->decode($jsontxt);
# ignore packets not for us
if ($msg->{_tag} ne $tag) {
next;
}
# Save most recent error for return
if ($msg->{_type} eq 'error') {
$error = $msg;
next;
}
if ($msg->{_type} eq 'end') {
if ($error) {
# TODO: an error channel
return undef;
}
return $db;
}
if ($msg->{_type} eq 'row') {
delete $msg->{_tag};
delete $msg->{_type};
push @$db, $msg;
next;
}
# Ignore any unknown _type
}
}
sub read {
my $self = shift;
my $cmdline = shift;
my $tag = $self->{tag}++;
# TODO:
# Add a read cache
$self->_tx(sprintf("r %i %s", $tag, $cmdline));
return $self->_rx($tag);
}
1;
package main;
use warnings;
use strict;
my $config = {
edge_pkts => {
p2p_tx_pkt => {
label => 'Peer to Peer tx rate',
type => 'DERIVE',
min => 0,
},
p2p_rx_pkt => {
label => 'Peer to Peer rx rate',
type => 'DERIVE',
min => 0,
},
super_tx_pkt => {
label => 'Peer to Supernode tx rate',
type => 'DERIVE',
min => 0,
},
super_rx_pkt => {
label => 'Peer to Supernode rx rate',
type => 'DERIVE',
min => 0,
},
super_broadcast_tx_pkt => {
label => 'Broadcast to Supernode tx rate',
type => 'DERIVE',
min => 0,
},
super_broadcast_rx_pkt => {
label => 'Broadcast to Supernode rx rate',
type => 'DERIVE',
min => 0,
},
transop_tx_pkt => {
label => 'Transform tx rate',
type => 'DERIVE',
min => 0,
},
transop_rx_pkt => {
label => 'Transform rx rate',
type => 'DERIVE',
min => 0,
},
},
edge_counts => {
edges => {
label => 'Current known peers',
type => 'GAUGE',
},
supernodes => {
label => 'Current known supernodes',
type => 'GAUGE',
},
},
supernode_pkts => {
errors_tx_pkt => {
label => 'Error rate',
type => 'DERIVE',
min => 0,
},
reg_super_rx_pkt => {
label => 'Connect rate',
type => 'DERIVE',
min => 0,
},
reg_super_nak => {
label => 'Connect error rate',
type => 'DERIVE',
min => 0,
},
forward_tx_pkt => {
label => 'Packets forwarded rate',
type => 'DERIVE',
min => 0,
},
broadcast_tx_pkt => {
label => 'Broadcast packet rate',
type => 'DERIVE',
min => 0,
},
},
supernode_counts => {
edges => {
label => 'Current known edges',
type => 'GAUGE',
},
communities => {
label => 'Current known communities',
type => 'GAUGE',
},
},
};
my $fetchinfo = {
edge_pkts => {
port => 5644,
read => "packetstats",
},
edge_counts => {
port => 5644,
count => [
"edges",
"supernodes",
],
},
supernode_pkts => {
port => 5645,
read => "packetstats",
},
supernode_counts => {
port => 5645,
count => [
"edges",
"communities",
],
},
};
sub do_config {
my $rpc = shift;
my $name = shift;
print("graph_title n2n $name status\n");
print("graph_category network\n");
my @names;
while (my ($fieldname, $field) = each(%{$config->{$name}})) {
push @names, $fieldname;
while (my ($key, $val) = each(%{$field})) {
print($fieldname.'.'.$key," ",$val,"\n");
}
}
# Ensure stable order
print("graph_order ", join(' ', sort(@names)), "\n");
}
sub do_fetch {
my $rpc = shift;
my $name = shift;
my $db;
my $read_table = $fetchinfo->{$name}->{read};
if (defined($read_table)) {
$db = $rpc->read($read_table);
for my $row (@$db) {
my $type = $row->{type};
delete $row->{type};
while (my ($key, $val) = each(%{$row})) {
my $metricname = $type."_".$key;
print($metricname,".value ",$val,"\n");
}
}
}
my $count_tables = $fetchinfo->{$name}->{count};
if (defined($count_tables)) {
for my $table (@{$count_tables}) {
$db = $rpc->read($table);
print($table,".value ", scalar(@$db), "\n");
}
}
}
sub do_autoconf {
# quick check to see if this plugin should be enabled
if (`pgrep supernode`) {
print("yes\n");
} elsif (`pgrep edge`) {
print("yes\n");
} else {
print("no - neither edge nor supernode are running\n");
}
}
sub do_suggest {
my $ports = {};
if (`pgrep supernode`) {
$ports->{5645}=1;
}
if (`pgrep edge`) {
$ports->{5644}=1;
}
while (my ($name, $info) = each(%{$fetchinfo})) {
my $port = $info->{port};
next if (!defined($port)); # this not a real fetchinfo
next if (!defined($ports->{$port})); # not linked to a running daemon
print($name,"\n");
}
}
my $subc = {
'fetch' => \&do_fetch,
'config' => \&do_config,
'autoconf' => \&do_autoconf,
'suggest' => \&do_suggest,
};
sub main() {
my $name = $ARGV[1] || $0;
$name =~ s%^.*/n2n_([^/]+)%$1%;
my $port = $fetchinfo->{$name}->{port};
my $rpc = JsonUDP->new($port);
my $cmd = $ARGV[0];
if (!defined($cmd)) {
$cmd = 'fetch';
}
my $func = $subc->{$cmd};
if (!defined($func)) {
die("bad sub command");
}
return $func->($rpc, $name);
}
main();