mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-25 18:38:30 +00:00
Rewriting Ping plugin in perl
* Merging existing plugins
This commit is contained in:
parent
8d941d04d0
commit
dca361d029
1 changed files with 176 additions and 83 deletions
|
@ -1,98 +1,191 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
# ping revision 2 (Jul 2012)
|
=cut
|
||||||
#
|
|
||||||
# This plugin shows ping statistics for several hosts on a single graph
|
|
||||||
#
|
|
||||||
# Configuration:
|
|
||||||
# Add [ping] section with 'hosts' set to space-separated list of hostnames or addresses.
|
|
||||||
# You can prefix host name with '<type>:' to change IP resolution mode,
|
|
||||||
# e.g. 'AAAA:domain.tld' will request IPv6 record.
|
|
||||||
# Always prefix IPv6 addresses with 'AAAA:' (internal limitation).
|
|
||||||
#
|
|
||||||
# Dependencies:
|
|
||||||
# host util is required
|
|
||||||
#
|
|
||||||
# OS:
|
|
||||||
# Linux
|
|
||||||
#
|
|
||||||
# Author: Artem Sheremet <dot.doom@gmail.com>
|
|
||||||
#
|
|
||||||
|
|
||||||
function normalize() {
|
=head1 NAME
|
||||||
echo ${1//[^a-zA-Z0-9]/_}
|
|
||||||
|
ping - Plugin to monitor ping times
|
||||||
|
|
||||||
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
|
ping_args - Arguments to ping (default "-c 2 -w 1")
|
||||||
|
ping_args2 - Arguments after the host name (required for Solaris)
|
||||||
|
ping - Ping program to use
|
||||||
|
ping6 - Ping program to use with IPv6
|
||||||
|
hosts - List of comma-separated hosts to ping (IPv4/6 address or FQDN)
|
||||||
|
You can prepend host name with:
|
||||||
|
'A:' - to resolve all IPv4 addresses
|
||||||
|
and create an entry per address (requires 'host' program)
|
||||||
|
'AAAA:' - the same for IPv6 (requires 'host' program)
|
||||||
|
'6:' - do not try to resolve, but use ping6 for this host
|
||||||
|
names - Friendly display name of each host given in the "hosts" parameter (comma-separated list).
|
||||||
|
If not set, "hosts" elements will be used
|
||||||
|
fork - If set to non-zero, fork each ping into parallel process to ping asynchronously
|
||||||
|
|
||||||
|
Configuration example
|
||||||
|
|
||||||
|
[ping]
|
||||||
|
env.hosts mail.example.org,6:www.example.org,AAAA:search.example.org
|
||||||
|
env.names Mail,Web,Search
|
||||||
|
env.fork yes
|
||||||
|
|
||||||
|
Configuration example for Solaris
|
||||||
|
|
||||||
|
[multiping]
|
||||||
|
env.host www.example.org mail.example.org
|
||||||
|
env.ping_args -s
|
||||||
|
env.ping_args2 56 2
|
||||||
|
|
||||||
|
You can also append plugin name with '_packetloss' to get packet loss statistics.
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Original Perl script Copyright (C) 2008 Thomas Gutzler (thomas.gutzler@gmail.com)
|
||||||
|
Original Shell script Copyright (C) 2004 Jimmy Olsen
|
||||||
|
|
||||||
|
=head1 LICENSE
|
||||||
|
|
||||||
|
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; version 2 dated June,
|
||||||
|
1991.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
|
#%# family=manual
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Munin::Plugin;
|
||||||
|
|
||||||
|
my $ping = exists $ENV{ping} ? $ENV{ping} : "ping";
|
||||||
|
my $ping6 = exists $ENV{ping6} ? $ENV{ping6} : "ping6";
|
||||||
|
my $ping_args = exists $ENV{ping_args} ? $ENV{ping_args} : "-c 2 -w 1";
|
||||||
|
my $ping_args2 = exists $ENV{ping_args2} ? $ENV{ping_args2} : "";
|
||||||
|
my $fork = exists $ENV{fork} ? $ENV{fork} : 0;
|
||||||
|
my $packetloss_mode = ($0 =~ /_packetloss$/);
|
||||||
|
|
||||||
|
my @host_options = exists $ENV{hosts} ? split(/,/, $ENV{hosts}) : "A:www.google.com";
|
||||||
|
|
||||||
|
# bare addresses
|
||||||
|
my @host_addrs = @host_options;
|
||||||
|
|
||||||
|
# ping program to use
|
||||||
|
my @host_ping = ($ping) x @host_options;
|
||||||
|
|
||||||
|
# resolve record type, if specified
|
||||||
|
my @host_resolv = (0) x @host_options;
|
||||||
|
|
||||||
|
my $config_mode = ($ARGV[0] and $ARGV[0] eq 'config');
|
||||||
|
if ($config_mode) {
|
||||||
|
print "graph_title " . ($packetloss_mode ? "Ping packet loss" : "Ping times") . "\n";
|
||||||
|
print "graph_args --base 1000 -l 0\n";
|
||||||
|
print "graph_vlabel " . ($packetloss_mode ? "packets" : "seconds") . "\n";
|
||||||
|
print "graph_category network\n";
|
||||||
|
print "graph_info This graph shows ping " . ($packetloss_mode ? "packet loss" : "RTT") . " statistics.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
function host_type() {
|
for (my $host_option = 0; $host_option < @host_options; ++$host_option) {
|
||||||
case $1 in
|
my $h_addr = $host_options[$host_option];
|
||||||
*:*)
|
my @config = split(/:/, $h_addr, 2);
|
||||||
echo ${1/:*/}
|
if ($#config) {
|
||||||
;;
|
my $h_ping = $ping;
|
||||||
*)
|
my $h_resolv = 0;
|
||||||
echo A
|
if ($config[0] eq "6") {
|
||||||
;;
|
# user wants this host to be pinged via IPv6
|
||||||
esac
|
$h_ping = $ping6;
|
||||||
|
$h_addr = $config[1];
|
||||||
|
} elsif ($config[0] eq "A") {
|
||||||
|
# user wants this host to be resolved via IPv4
|
||||||
|
$h_resolv = "A";
|
||||||
|
$h_addr = $config[1];
|
||||||
|
} elsif ($config[0] eq "AAAA") {
|
||||||
|
# user wants this host to be resolved as IPv6
|
||||||
|
$h_resolv = "AAAA";
|
||||||
|
$h_addr = $config[1];
|
||||||
|
$h_ping = $ping6;
|
||||||
|
} elsif ($config[0] =~ /^[[:xdigit:]]+$/) {
|
||||||
|
# this is IPv6 addr
|
||||||
|
$h_ping = $ping6;
|
||||||
|
} else {
|
||||||
|
# let 'host' decide what resolve type do we need
|
||||||
|
$h_resolv = $config[0];
|
||||||
|
$h_addr = $config[1];
|
||||||
|
}
|
||||||
|
$host_addrs[$host_option] = $h_addr;
|
||||||
|
$host_resolv[$host_option] = $h_resolv;
|
||||||
|
$host_ping[$host_option] = $h_ping;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function host_name() {
|
# display names
|
||||||
echo "${1/*:/}"
|
my @host_names = exists $ENV{names} ? split(/,/, $ENV{names}) : @host_addrs;
|
||||||
|
|
||||||
|
if (@host_names != @host_addrs) {
|
||||||
|
print "Warning: host names specified does not match addresses\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
function ipof() {
|
# forked children
|
||||||
host -t $(host_type $1) $(host_name $1) |
|
my @children = ();
|
||||||
sort | grep -Eo 'address .*' | cut -d' ' -f2 | head -1
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "$1" == "config" ]]; then
|
for (my $host_i = 0; $host_i < @host_addrs; ++$host_i) {
|
||||||
echo 'graph_title Ping statistics
|
my @h_addrs = ($host_addrs[$host_i]);
|
||||||
graph_vlabel Time,ms
|
my $h_ping = $host_ping[$host_i];
|
||||||
graph_category network
|
my $h_resolv = $host_resolv[$host_i];
|
||||||
graph_info ping statistics for several hosts'
|
my $h_name = $host_names[$host_i];
|
||||||
for host in $hosts; do
|
|
||||||
echo "$(normalize $host).label $(host_name $host) ($(ipof $host))"
|
|
||||||
done
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
SYNC_FILE=/tmp/munin-ping-sync
|
if ($h_resolv) {
|
||||||
echo -n >"$SYNC_FILE"
|
# we have to resolve the host to (probably multiple) addresses
|
||||||
|
my $h_base_addr = pop @h_addrs;
|
||||||
COUNT=0
|
my @host = `host -t $h_resolv $h_base_addr`;
|
||||||
for host in $hosts; do
|
chomp @host;
|
||||||
{
|
for (my $h_host_i = 0; $h_host_i < @host; ++$h_host_i) {
|
||||||
case $(host_type $host) in
|
my $h_host = $host[$h_host_i];
|
||||||
AAAA)
|
my ($h_addr) = $h_host =~ /address (.*)$/;
|
||||||
PING=ping6
|
if ($h_addr) {
|
||||||
;;
|
push @h_addrs, $h_addr;
|
||||||
*)
|
|
||||||
PING=ping
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
TIME=$($PING -w 1 -c 1 `host_name $host` | awk '
|
|
||||||
BEGIN {
|
|
||||||
found = 0
|
|
||||||
t = 0
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$1 == "rtt" { found = 1; t = $4; }
|
for (my $h_addr_i = 0; $h_addr_i < @h_addrs; ++$h_addr_i) {
|
||||||
|
my $h_addr = $h_addrs[$h_addr_i];
|
||||||
END {
|
my $h_cur_name = $h_resolv ? $h_name . " ($h_addr)" : $h_name;
|
||||||
if (found == 1) {
|
my $h_norm_name = clean_fieldname($h_cur_name);
|
||||||
split(t, parts, "/");
|
if ($config_mode) {
|
||||||
print parts[1]
|
print "$h_norm_name.min 0\n$h_norm_name.label $h_cur_name\n$h_norm_name.draw LINE2\n";
|
||||||
} else {
|
} else {
|
||||||
print "U"
|
my $pid = $fork ? fork() : -1;
|
||||||
|
if ($pid <= 0) {
|
||||||
|
# either we can't fork, or don't want to, or we are child
|
||||||
|
my @ping = `$h_ping $ping_args $h_addr $ping_args2`;
|
||||||
|
chomp @ping;
|
||||||
|
my $ping = join(" ", @ping);
|
||||||
|
my $ping_time = ($1 / 1000) if ($ping =~ m@min/avg/max.*\s\d+(?:\.\d+)?/(\d+(?:\.\d+)?)/\d+(?:\.\d+)?@);
|
||||||
|
my $packet_loss = $1 if ($ping =~ /(\d+)% packet loss/);
|
||||||
|
print "$h_norm_name.value ". ($packetloss_mode ? $packet_loss : $ping_time) . "\n";
|
||||||
|
if ($pid == 0) {
|
||||||
|
# this is a child process, don't forget to exit
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
# in parent
|
||||||
|
push @children, $pid;
|
||||||
}
|
}
|
||||||
')
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
echo $(normalize $host).value $TIME
|
for (my $child_i = 0; $child_i < @children; ++$child_i) {
|
||||||
echo ok >>"$SYNC_FILE"
|
waitpid($children[$child_i], 0);
|
||||||
} &
|
}
|
||||||
let COUNT=$COUNT+1
|
|
||||||
done
|
|
||||||
|
|
||||||
# wait for background processes to finish
|
|
||||||
while [ $(wc -l <"$SYNC_FILE") -lt $COUNT ]; do
|
|
||||||
sleep 0.2
|
|
||||||
done
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue