0  #!/usr/local/bin/perl
1  # file: check_servers
2  # author: Lincoln Stein
3  
4  use strict;
5  use IO::File;
6  use LWP::Simple;
7  use Net::SMTP;
8  use POSIX 'strftime';
9  use Getopt::Long;
10  
11  use constant DEFAULT_LOG    => '/var/log/www/stats';
12  use constant DEFAULT_URL    => '/status?auto';
13  
14  my ($SRVR_LIST,$ALERT,$LOG,$URL,%STATUS);
15  my $TIME = strftime("%d-%b-%Y %H:%M",localtime);
16  
17  GetOptions (
18              'servers=s' => \$SRVR_LIST,
19              'alert=s'   => \$ALERT,
20              'log=s'     => \$LOG,
21              'url=s'     => \$URL,
22              ) || die <<USAGE;
23  Usage: $0 [options] [servers...]
24    Check the status of a list of Web servers.
25  Options:
26    -servers <path>     File containing list of servers
27    -alert   <address>  E-mail address for server down warnings
28    -log     <path>     Directory to log status reports to
29    -url     <url>      URL to fetch to check status
30  USAGE
31      ;
32  
33  # set up defaults
34  $LOG   ||=  DEFAULT_LOG;
35  $ALERT ||=  $ENV{USER};
36  $URL   ||=  DEFAULT_URL;
37  
38  # get list of servers to fetch
39  my @SERVERS = @ARGV;
40  
41  # if -servers was specified, read server names from a file
42  if ($SRVR_LIST) {
43      my $fh = IO::File->new($SRVR_LIST) || die "Can't open $SRVR_LIST: $!";
44      chomp(my @servers = <$fh>);
45      push(@SERVERS,@servers);
46  }
47  
48  foreach my $server (@SERVERS) {
49      my $content = get("http://$server$URL");
50      %STATUS = $content =~ /^(.+): ([\d.Ee-]+)$/mg;
51      write_log($server);
52      send_alert($server) unless exists $STATUS{'Total Accesses'};
53  }
54  
55  sub write_log {
56      my ($server) = @_;
57      my $logfile =  "$LOG/$server";
58      my $exists = -e $logfile;
59      my $fh = IO::File->new(">>$logfile");
60      die "can't open $logfile for appending: $!" unless $fh;
61      unless (exists $STATUS{'Total Accesses'}) {
62          print $fh $TIME,"\t** SERVER UNREACHABLE **\n";
63          return;
64      }
65      # these lines control the format production.
66      select $fh;               # select the log file
67      $^ = 'LOG_TOP';           # set the top of form text
68      $~ = 'LOG';               # set the format for the body
69      $- = 100 if $exists;      # inhibit header except for first time called
70      write;
71      $fh->close;
72  }
73  
74  sub send_alert {
75      my $server = shift; 
76      chomp(my $hostname = `hostname -d`);
77      my $smtp = Net::SMTP->new('localhost',Hello=>$hostname);
78      $smtp->mail($ENV{USER});
79      $smtp->to($ALERT);
80      $smtp->data();
81      $smtp->datasend(<<END);
82  From: "check servers program" <$ENV{USER}\@$hostname>
83  To: $ALERT
84  Subject: $server is unreachable
85  
86  At $TIME the check_servers program tried to contact the
87  Web server named "$server", but there was no response.
88  
89  Yours truly,
90  The check_servers program
91  END
92      $smtp->dataend;
93      $smtp->quit;
94  }
95  
96  format LOG_TOP=
97      Date  Requests  kB  Load  Uptime  R/sec  B/sec  B/req  Busy  Idle
98  .
99  format LOG=
100  @<<<<<<<<<<<<<<<< @###### @####### @#.## @####### @#.## @###.# @#### @## @###
101  { $TIME,@STATUS{'Total Accesses','Total kBytes',
102                  'CPULoad','Uptime','ReqPerSec',
103                  'BytesPerSec','BytesPerReq',
104                  'BusyServers','IdleServers'}
105  }
106  .