summaryrefslogtreecommitdiffstats
path: root/ping-monitor.pl
blob: 442379da94a15c03d6abc57ba7308fe1bd6fd278 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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/max time: %0.2fms/%0.2fms/%0.2fms/%0.2fms", $stats->mean(), $stats->median(), $stats->standard_deviation(), $stats->max();
	}

	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);
}