http://qs1969.pair.com?node_id=57865

Our ISP at work is a bit unreliable, so we started keeping a log of how often our service goes up and down. I wrote this script to automate the task.

It works by using LWP to download the header of a reliable site every $interval seconds. It makes a log entry every time the service goes up or down.

Many thanks to tye and arhuman, who helped me with a problem of autoflushing the log in open, sleep, & print together cause an error.

Update: ybiC has posted a muchly improved version of this same program here.

An improvement would be to tell it to check a second site if the first one fails.

-zeno

=head1 NAME inet_log.pl =head1 DESCRIPTION Keeps a log of internet up and down time =head1 AUTHOR zeno =head1 SYNOPSIS perl inet_log.pl [name_of_logfile interval url_of_website] =head1 ARGUMENTS name_of_logfile - text file to use as log file [display (-) by default] interval - interval in seconds between checks [600 seconds by default] url_of_website - URL of website to try [http://www.perlmonks.com by default] =cut #!/usr/bin/perl -w use LWP::Simple; use strict; use warnings; # log file (display by default) my $log = $ARGV[0] ||= '-'; # interval between checks (600) my $interval = $ARGV[1] ||= 600; # site to try (perlmonks by default) my $site = $ARGV[2] ||= 'http://www.perlmonks.com'; my $old_state; my $state; print "Creating Internet Uptime Log at $log "; print "testing $site every $interval seconds.\n"; #changed this to the two arg version for #version < 5.6 compatibility (thanks ybiC) open (OUT, ">>$log") or die "can't open $log: $!"; #this way of setting AUTOFLUSH on the log I got #from tye and arhuman my $selected = select(OUT); $|++; select($selected); $old_state = (defined head($site)); print OUT (localtime).($old_state ? ": up\n" : ": down\n"); close OUT or die; print "".(localtime).($old_state ? ": up\n" : ": down\n"); while (1) { sleep $interval; $state = (defined head($site)); if ($state != $old_state) { # state changed open OUT,">>",$log or die "can't open $log: $!"; print OUT (localtime).($state ? ": up\n" : ": down\n"); close OUT or die; print "".(localtime).($state ? ": up\n" : ": down\n"); $old_state = $state; } }

Replies are listed 'Best First'.
Re: Internet Connection Uptime Logger (ICMP or HTTP)
by ybiC (Prior) on Feb 12, 2001 at 23:28 UTC
    That's pretty cool, zeno.   8^)

    One reason for fetching page headers instead of using ping is if you can't run the script from a host in your DMZ, and your firewall blocks ICMP.   It also eliminates false negatives if the website you pick doesn't respond to ICMP.   Or you could use this goody to nail up a dial connection - some ISPs don't hold a line up for ICMP but will, of course, for HTTP.

    BTW, I changed the open OUT,">>",$log lines like so: open (OUT, ">>$log") to get rid of this error:
    Too many arguments for open at lines (open OUT) near "$log or"
    Perl 5.00503 on Debian 2.2.
        cheers,
        Don
        striving for Perl Adept
        (it's pronounced "why-bick")

      Good point ybiC. There's no reason for me to use the three argument syntax, and it causes it to be incompatible with previous versions. I've changed the perlfunc:open code to your suggestion. Thanks! -zeno

(code) Re: Internet Connection Uptime Logger (mucked over)
by ybiC (Prior) on Feb 21, 2001 at 07:29 UTC
    Per zeno's request, here's my butchering of his cool code.   I don't see that mine's better - is just tweaked to suit my own porpoises.
        cheers,
        Don
        striving for Perl Adept
        (it's pronounced "why-bick")

    Update:
    perldoc inet_log.pl for details.

    • 2001-04-25   06:00   And more re-rewriting.
    • 2001-04-23     Substantial re-rewrite.
    • 2001-02-13     Initial fork
    #!/usr/bin/perl -wT # inet_log.pl # pod at tail use strict; use LWP::UserAgent; use Time::localtime; ### Begin Config Parameters ### my %parm = ( log => 'inet_log.log', interval => 300, timeout => 120, browser => 'Mozilla/5.0 (X11; U; Linux 2.2.17 i586; en-US; m18)', ); my @hosts = qw( www.w3c.org www.cpan.org www.perl.com freshmeat.net www.cisco.com www.useit.com www.google.com alistapart.com www.debian.org ftp.debian.org www.weather.com www.oreilly.com www.slashdot.org www.perlmonks.org www.linuxgazette.com ); my %proxy = ( use => 0, auth => 0, host => '', port => '', id => '', pass => '', ); ### End Config Parameters ### open (LOG, "> $parm{log}") or die "\nError opening $parm{log}:\n $! +"; my $selected = select(LOG); $|++; select($selected); print "\n", " Query a web host every $parm{interval} seconds\n", " Log: $parm{log}\n", " Program: $0\n", " LWP: $LWP::VERSION\n", " Perl: $]\n", " OS: $^O\n"; print " Proxy: $proxy{host}:$proxy{port}\n" if ($proxy{use} = += 1); print " Proxy user: $proxy{id}\n" if ($proxy{auth} +== 1); print "\n", " Target hosts:\n"; print " $_\n" for (@hosts); =cut if ($proxy{use} == 1) { Net::Ping::Improved unless (...) { print" Proxy not accessible\n\n"; exit; } } =cut print "\n Querying web hosts (1 = success, 0 = no response)\n"; my $old_success = 3; # first contact gets logged while (1) { for (@hosts) { my ($success, $request); my $ua = LWP::UserAgent->new; $ua -> agent("$parm{browser}"); $ua -> timeout("$parm{timeout}"); if ($proxy{use} == 1) { $ua -> proxy('http',"http://$proxy{host}:$proxy{port}"); $ua -> no_proxy($proxy{host}); } if ($proxy{auth} == 1) { $request -> proxy_authorization_basic ("$proxy{id}", "$proxy{pass}"); } $request = HTTP::Request->new('GET',"http://$_"); my $response = $ua->request($request); if ($response->is_success()) {$success = 1;} elsif ($response->is_error()) {$success = 0;} PrintCon("$success", "$_"); if ($success != $old_success) { # has connection status cha +nged? open (LOG, ">> $parm{log}") or die "\nError opening $parm{ +log}: $!"; PrintLog("$success", "$_"); $old_success = $success; } sleep $parm{interval}; } } ###################################################################### +#### sub PrintCon { my $print_state = $_[0]; my $host = $_[1]; printf " %4d-%2d-%2d, %2d:%2d:%2d, ", localtime->year()+1900, localtime->mon()+1, localtime->mday(), localtime->hour(), localtime->min(), localtime->sec(), ; print " $print_state, $host,\n"; } ###################################################################### +#### sub PrintLog { my $print_state = $_[0]; my $host = $_[1]; printf LOG " %4d-%2d-%2d, %2d:%2d:%2d, ", localtime->year()+1900, localtime->mon()+1, localtime->mday(), localtime->hour(), localtime->min(), localtime->sec(), ; print LOG " $print_state, $host,\n"; close LOG or die "\nError closing $parm{log}: $!"; } ###################################################################### +#### =head1 Name inet_log.pl =head1 Description Log Internet connection drops, or nail up a dial connection. Use LWP to periodically request a page from configured list of webhos +ts. Doesn't use simple ping because: - ISP routers often not configured for ICMP as "interesting traffic +" where HTTP generally is. - Some sites block ICMP at their outside DMZ router. - Allows you to run this script from inside a firewalled location for other purposes. Logs only instances of change in response (pass|fail). =head1 Usage No switches or syntax. Config parameters near head of script. =head1 Author ybiC =head1 Credits Started from good monk zeno's cool inet_log.pl http://www.perlmonks.org/index.pl?node_id=57865 =head1 Tested LWP 5.51 Perl 5.00503 Debian 2.2r3 =head1 Updates 2001-04-25 06:00 Add module and Perl versions display. Simplify code for opening messages. Add qw() to declaration of @hosts to eliminate mess o' quotes+comma +s. Unsubify LWP - move Fetch code to main body of script. Use $_ with @hosts to eliminate global $host. Fix 'uninitialized value' re $print_state by quoting properly in Print(Log|Con) calls. Add support for authenticated proxy. Break %global out into %proxy and %parm. Add if(){...} loops for proxy{use} and proxy{auth} Minor format & pod tweaks. 2001-04-23 22:40 Hashamify passel o' scalar vars. Un-subify to reduce number of global vars. Replace 'use vars qw()' with 'my (,)' so lexical not global. Mixed-case names for remaining subroutines, and no ampersan. Remove unecessary doublequotes around variables. Fix 'scalar found where' errors by adding qq// to Print(Con|Log) ca +lls. Reformat for max 75 chars/line. 2001-02-14 Replace LWP::Simple with LWP::UserAgent. Add proxy, timeout, useragent. Move $ua section to sub since is called twice. Add Time::localtime, printf. because no comprendo good monk zeno's time syntax. Move sleep to end of while(1) section so no wait after hit proxy. 2001-02-13 Fork from zeno's cool script. Minor style stuff to personal taste. Multiple hosts target rotation - avoid excessive hits on any one ho +st. Move redundant code to subroutines. Output format to CSV for reporting. Add "use vars qw()" instead of empty 'my blah's'. Hit local proxy first before hitting Internet hosts. assumes proxy is also HTTP server. =head1 Todos Ping proxy with Net::Ping(|::(Improved|External)). Test $proxy{user} and $proxy{pass}. Test on Win32 - ActiveState, Cygwin, etc. Randomize @hosts selection, and $parm{interval} ~1-4 minutes. Background with (fork|Proc::Daemon|??) so can kill xterm after launch +ing. If connection fails, immediately try next host. =cut
      It's been quite a while since this was posted but I did, however, still find it quite useful. I have updated the code slightly implementing a couple of the Todos. I'll try and figure out how to post my updated version. Regards, Brad
Re (boo): Internet Connection Uptime Logger
by boo_radley (Parson) on Feb 12, 2001 at 20:45 UTC
    I'm curious as to why the criteria is a webpage's headers, rather than ability to ping out. What drove that decision?

      Hi boo_radley
      That's an excellent question. I thought getting the header would simulate the action we want our users to be able to do: accessing the internet using a browser.

      However, now that you mention it, maybe just being able to ping a site would be okay, as long as we were pinging a URL and not an IP address. Why? Because our service provider often has problems with their DNS servers, too. Thanks for the input.
      -zeno

Re: Internet Connection Uptime Logger
by Anonymous Monk on Feb 02, 2004 at 00:54 UTC
    Isn't this kind of obsoleted now that ICPLD is available?
      Sure is! Btw, is http://icpld.northernmost.org the official site?