#!/usr/bin/perl -w # productname: loadwatch # productrelease: V0.1 # # copyright 2005 by kapper.net # reach kapper.net at http://kapper.net/ or via postal mail to: # kapper & partner communications keg, kapper.net gmbh # loeblichgasse 6, A-1090 Vienna, Austria # development-team: mm@kapper.net, hk@kapper.net # # 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; either version 2 of the License, or (at your option) # any later version. # # 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., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # http://www.gnu.org/licenses/gpl.txt # ---------------------------------------------------- # project started: 15.02.2005 # ---------------------------------------------------- # synopsis: # script checks the /proc/loadavg for the systemload and if that is critical # sends an email to notify its master and writes to syslog that the problem # arose. # # requirements: Mail::Sendmail perl-class (available from http://alma.ch/perl/mail.html or CPAN) # local sendmail/postfix/whatever mailserver to deliver the sent email if required # alternatively you can edit Sendmail.pm to have your smtp-server globally set # # currently hardcoded: loadavg of >5 for 15 minutes and >8 for 5 minutes and >10 for 1 minute is # classified as critical load # # usage: loadwatch # # possible parameters # ------------------- # # --check-load | -c # reads output of "/proc/loadavg" # if there is a problem write to syslog and optional send email # --sendto | -s # this is an optional parameter, if used, it requires an email address, # to which a possible problem-report is sent. # # # # History: # -------- # 15.02.2005 hk adopt from httpdcheck perl-code # use strict; use Fcntl; # for file io use Mail::Sendmail; # for sendmail class use Sys::Syslog; # for notification of syslog-services my $LAVG = "/proc/loadavg"; # file that contains loadavg interface # if needed please change the above systemcall and filepath/-name. # possible params my $PARAM_CHECK = "--check-load"; my $PARAM_SEND = "--sendto"; my $PARAM_CHECK_SHORT = "-c"; my $PARAM_SEND_SHORT = "-s"; # constants my $PDEFAULT = 0b0000; my $callparam = $PDEFAULT; # don't ask ;-) my $READ = 0b1000; my $CHECK = 0b0100; my $SEND = 0b0010; my $EQUAL = 123443; # here it means "loadavg is ok" my $NOTEQUAL = 394342; # here it means do a problem-report and restart #my $FROM = ""; # set to get a specific from-address my $SUBJECT = "load average critcal: " . `hostname`; # -------------------------------------------- # compares the submitted strings on the loadavg # above specified constants for EQUAL and NOTEQUAL get returned. # parameters are oneminute fiveminutes fifteenminutes sub compare { my $mone = $_[0]; my $mfive = $_[1]; my $mfifteen = $_[2]; my $rc = $NOTEQUAL; my ($one, $five, $fifteen); # - - - - - - - - open(LOAD,$LAVG) || return $NOTEQUAL; # meaning: "4564 Cannot read load average: $!" my $line = ; $line =~ /^(\d+\.\d+)\s*(\d+\.\d+)\s*(\d+\.\d+)/o; close LOAD; $one = $1; $five = $2; $fifteen = $3; if ($one >= $mone) { $rc = $NOTEQUAL; } elsif ($five >= $mfive) { $rc = $NOTEQUAL; } elsif ($fifteen >= $mfifteen) { $rc = $NOTEQUAL; } else { $rc = $EQUAL; # all tests are fine it seems } return ($rc); } # -------------------------------------------------------------------------- # give the user some hints on how to use... sub usage { my $usageinfo = ""; $usageinfo .= "---------------------------------------------------------\n"; $usageinfo .= "usage: $0 \n\n"; $usageinfo .= "possible parameters\n"; $usageinfo .= "-------------------\n"; $usageinfo .= "\t--check-load | -c\n"; $usageinfo .= "\t checks for a decent loadavg and escalates if necessary\n"; $usageinfo .= "\t if there is a problem it reports to STDOUT\n"; $usageinfo .= "\t --sendto | -s \n"; $usageinfo .= "\t this is optional - if used - it requires an email address,\n"; $usageinfo .= "\t a possible problem is mailed to the given address.\n"; $usageinfo .= "Have fun and may your server never overload ;)\n"; $usageinfo .= "copyright 2005 by http://kapper.net/\n\n"; $usageinfo .= "---------------------------------------------------------\n"; die "$usageinfo"; } # ---------------------------------------- # main { my $param = shift @ARGV; # shift gets the next parameter and cuts it off ARGV my $infotxt = ""; my $program = "loadwatch"; my ($mailadr,$cmdreply,$rc,$rc1); my %mail; # sendmail needs this while (defined $param) # as long as there are parameters { if (($param eq $PARAM_CHECK) || ($param eq $PARAM_CHECK_SHORT)) { $callparam |= $CHECK; } elsif (($param eq $PARAM_SEND) || ($param eq $PARAM_SEND_SHORT)) { $callparam |= $SEND; $mailadr = shift @ARGV; # next parameter needs to be an email address if (!($mailadr)) { $callparam = $PDEFAULT; # default value ... means error and needs to show usage } else { if (!($mailadr =~m/.+\@.+\..+/)) { $callparam = $PDEFAULT; # default value ... means error and needs to show usage } } } else # no params { $callparam = $PDEFAULT; # default value ... means error and needs to show usage } $param = shift @ARGV; # get next parameter } if ($callparam == ($SEND)) { $callparam = $PDEFAULT;} # no sendonly option &usage if ($callparam == $PDEFAULT); if (($callparam & $CHECK) == $CHECK) { $rc = compare(10,8,5); # loadavg for 1, 5, 15 minutes max # test $rc = compare(1,1,1); # loadavg for 1, 5, 15 minutes max openlog($program, 'cons,pid', 'user'); syslog('info', 'load-checking.'); closelog(); if ($rc == $NOTEQUAL) { open(LOAD,$LAVG) || print STDERR "ERROR: Cannot read load average: $!"; my $line = ; close LOAD; openlog($program, 'cons,pid', 'user'); syslog('info', 'load-avg is high: '. $line); closelog(); $infotxt = "----------------------------------------\n"; $infotxt .= "Attention! server-load is high! \n"; $infotxt .= "----------------------------------------\n"; $infotxt .= "current load average status:\n"; $infotxt .= "----------------------------------------\n"; $infotxt .= "$line"; $infotxt .= "----------------------------------------\n"; $infotxt .= "please check your server.\n"; $infotxt .= "load-status-check is sponsored by http://kapper.net/\n"; } if (($callparam & $SEND) == $SEND) { if ($infotxt ne "") { # set mail parameters for sending %mail = ( To => $mailadr, From => $mailadr, Subject => $SUBJECT, Message => $infotxt );# sendmail(%mail) or die $Mail::Sendmail::error; #print "OK. Log says:\n", $Mail::Sendmail::log; } } else { if ($infotxt) # if param = --check without email { print STDOUT "\n$infotxt\n"; } } } } # end main