summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xping-monitor.pl94
1 files changed, 94 insertions, 0 deletions
diff --git a/ping-monitor.pl b/ping-monitor.pl
new file mode 100755
index 0000000..a435cee
--- /dev/null
+++ b/ping-monitor.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use autodie;
+use Data::Dumper;
+use Time::HiRes qw(time);
+use Statistics::Descriptive;
+
+=head1 NAME
+ping-monitor.pl - Live ping statistics
+
+=head1 SYNOPSIS
+
+ping-monitor.pl <host>
+
+=head1 DESCRIPTION
+
+ping-monitor.pl provides live mean, median, standard deviation and packet loss
+statistics similar to ping(8). The statistics are calculated over the last 10
+seconds by default.
+
+=cut
+
+
+if (0+@ARGV < 1) {
+ print "usage: $0 <host>\n";
+ exit 0;
+}
+
+my $host = $ARGV[0];
+# a value < 0.2 requires root privileges
+my $frequency = 0.2;
+# 10 second average
+my $window_size = 10/$frequency;
+
+open my $ping, "-|", "ping -nDOi $frequency -W 1 $host";
+
+my @history;
+my $last_reply = 0;
+
+# ensure we are on a clean line for cleaning later
+printf "\n";
+
+while (<$ping>) {
+ next if m/^PING /;
+
+ if (m/^\[(?<ts>[0-9.]+)\] \d+ bytes from [^:]+: icmp_seq=\d+ ttl=\d+ time=(?<time>[0-9.]+) ms$/) {
+ push @history, {
+ timestamp => $+{ts},
+ time => $+{time},
+ };
+ $last_reply = $+{ts} if $+{ts} > $last_reply;
+ } elsif (m/^\[(?<ts>[0-9.]+)\] no answer yet for icmp_seq=\d+$/) {
+ push @history, {
+ timestamp => $+{ts},
+ time => undef,
+ };
+ }
+ if (0+@history > $window_size) {
+ splice @history, 0, 1;
+ }
+
+ my $avg_lost = 0.0;
+ my $stats = Statistics::Descriptive::Full->new();
+
+ for my $x (@history) {
+ $stats->add_data($x->{time}) if defined $x->{time};
+ $avg_lost += 1 if not defined $x->{time};
+ }
+
+ $avg_lost /= @history if @history > 0;
+ my $last_reply_diff = 0;
+ $last_reply_diff = time - $last_reply if $last_reply;
+
+ # clear 1 line
+ printf "[%dF", 0;
+
+ my @parts;
+
+ if ($stats->mean()) {
+ push @parts, sprintf "avg/median/stdev time: %0.2fms/%0.2fms/%0.2fms", $stats->mean(), $stats->median(), $stats->standard_deviation();
+ }
+
+ push @parts, sprintf "avg loss: %0.2f%%", $avg_lost*100 // 0.0;
+
+ if ($last_reply_diff > 0.5) {
+ push @parts, sprintf "last reply: %0.3fs ago", $last_reply_diff;
+ }
+
+ print join(", ", @parts)."\n";
+
+ #print Dumper(\@history);
+ #print Dumper($avg_time, $avg_lost, $last_reply);
+}