#!/usr/bin/perl # You may need to change this path to /usr/local/bin/perl # Path to sendmail $mailprog = '/usr/sbin/sendmail'; #************************************************************** # # Script to monitor server load automatically: PWSservermonitor V5.1 # # Written by: # Premier Website Solutions - http://www.premierwebsitesolutions.com # Created - October 20, 2004 (V1.0) # Modified - October 20, 2004 (V2.0) # - added ability to ignore some commands or users(*) # - added ability to specify minimum time between emails(*) # Modified - October 21, 2004 (V2.1) # - changed how it finds the starting point # Modified - October 22, 2004 (V2.2) # - adjustment for output on multiple CPU server # Modified - October 23, 2004 (V3.0) # - added monitoring of average server load # - adjustment for operation on multiple CPU server # Modified - October 23, 2004 (V3.5) # - changed how output is deciphered # - gives a cleaner output for your email # - added notification if output doesn't appear to work with script # Modified - November 27, 2004 (V4.0) # - adjusted for long running processes # - sends email warning for processes using over 1000 minutes CPU time # Modified - January 27, 2005 (V4.5) # - activated multiple checks per minute feature(*) # - modified email subject to give more detail for easier quick looking(*) # Modified - May 10, 2005 (V5.0) # - now ignores short term high load processes(*) # Last Modified - July 9, 2006 (V5.1) # - modified for top outputs with no decimal in CPU % and with decimal in time # # (*) features not in free version # Join my scripts club for $10 US and get access to full features of all scripts # www.premierwebsitesolutions.com/scripts/scriptsclub.pws # # # This script monitors your server load by issuing a "top" command and reading # it's data. It will email you if any single process is using over the limit you # specify for CPU or Memory load, or if the top 10 processes are using more than # your specified maximum. It will now also email you if the 5 minute or 15 minute # load average is above your specs. # # Provide and/or modify a few variables below, upload this script to anywhere on # your server and set a cron job to run it. # # MAKE SURE YOU SET YOUR EMAIL ADDRESS OR THE SCRIPT WILL BE USELESS # # I set my cron job to run every minute and have the script email me every 2 minutes # if the load stays high. # # # Registered users of this script will be notified of any future updates. # If you registered this copy with me, put your email here for future reference. # This copy is registered to: # #************************************************************** # Set these variables # If you get too many emails, you may want to increase one or more of these # maximum values or add processes to the commands to ignore list. # Maximum %CPU per process $maxcpu = 60; # Maximum %CPU - top 10 processes total $maxcputotal = 95; # Number of CPU's on server $CPUs = 1; # Maximum load average # Generally around 2 to 3 times the number of CPU's # Only watches the 5 and 15 minute averages. The 1 minute # average would send far too many warning emails. $maxloadave = 2.5; # Maximum %Memory per process $maxmem = 30; # Maximum %Memory - top 10 processes total $maxmemtotal = 80; # Email to send message to $email = 'you '; # Email to use as message sender # Change this one if you like $sender = 'Mike '; # Any name to let you know which server this came from $servername = "server1"; # When you are emailed about your server load, you can also have the # current "top" output sent in the email. If you do want it included, # change this option to Y. $includetop = "N"; #************************** # No further editing #************************** $cputotal = 0; $memtotal = 0; $messagecount = 0; $multicpu = ""; @messages = ""; $allprocesses = ""; &docheck; exit; sub docheck { @top = `top -n1 -bc`; foreach (@top) { chomp ($_); $_ =~ s/\r/\n/gs; $count++; if ($_ =~ /load average/) { $tmp = $_; $tmp =~ s/.*load average://; $tmp =~ s/ +//g; ($oneminuteave,$fiveminuteave,$fifteenminuteave) = split(/,/,$tmp); } if ($_ =~ /PID/ && $_ =~ /USER/ && $_ =~ /COMMAND/) { $commandline = $_; $commandline =~ s/^ +//g; $commandline =~ s/ +/\|/g; $line1 = $count; $line2 = $count + 11; } if ($count > $line1 && $count < $line2) { push(@processes,$_); } } $oneminuteavepercpu = $oneminuteave / $CPUs; $fiveminuteavepercpu = $fiveminuteave / $CPUs; $fifteenminuteavepercpu = $fifteenminuteave / $CPUs; if ($fiveminuteave > $maxloadave || $fifteenminuteave > $maxloadave) { $messagecount++; } else { } foreach (@processes) { chomp ($_); $_ =~ s/^ +//; $tmp2 = $_; $tmp = $_; $PID = $tmp; $PID =~ s/\s.*//; $tmp =~ s/^$PID\s+//; $USER = $tmp; $USER =~ s/\s.*//; $tmp =~ s/^$USER\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\D+//; $CPU = $tmp; $CPU =~ s/\s.*//; $tmp =~ s/^$CPU\s+//; $MEM = $tmp; $MEM =~ s/\s.*//; $tmp =~ s/^$MEM\s+//; $TIME = $tmp; $TIME =~ s/\s.*//; $tmp =~ s/^$TIME\s+//; if ($CPUs > 1) { $whichCPU = $tmp; $whichCPU =~ s/\s.*//; $tmp =~ s/^$whichCPU\s+//; $COMMAND = $tmp; $multicpu = " on CPU #" . $whichCPU; } else { $COMMAND = $tmp; } # Just in case the output wasn't read correctly if ($PID =~ /\D/) { $error = $error . "Process ID not read correctly\n"; } if ($CPU !~ /\d+\.?\d*/) { $error = $error . "CPU percentage not read correctly\n"; } if ($MEM !~ /\d+\.\d+/) { $error = $error . "Memory percentage not read correctly\n"; } if ($TIME =~ /\d+:\d+\.?\d*/) { ($minutes,$seconds) = split(/:/,$TIME); $running_time = "$minutes minutes and $seconds seconds"; } elsif ($TIME =~ /\d+m/) { $minutes =~ $TIME; $minutes =~ s/m$//; $running_time = "$minutes minutes"; if ($minutes > 999) { $running_time = $running_time . ", which may be a long time for a process to be running"; $messagecount++; } } else { $error = $error . "Time not read correctly\n"; } if ($error) {&sendmailerror;} $cputotal = $cputotal + $CPU; $memtotal = $memtotal + $MEM; $tmpmessage = "- The process ID #$PID under the user $USER is using $CPU\% CPU and $MEM\% Memory with the command $COMMAND which has been running$multicpu for $running_time.\n\n"; $allprocesses = $allprocesses . $tmpmessage; $CPUequiv = $CPU / $CPUs; if ($CPUequiv > $maxcpu || $MEM > $maxmem) { push (@messages,$tmpmessage); $messagecount++; } } $cputotalequiv = $cputotal / $CPUs; if ($cputotalequiv > $maxcputotal || $memtotal > $maxmemtotal) { push (@messages,"\n#####################################\n\nThe top 10 processes are using a total of $cputotal\% CPU and a total of $memtotal\% Memory. The process list will follow.\n\n"); push (@messages,"Here are the top 10 processes:\n\n$allprocesses\n\n"); $messagecount++; } if ($messagecount > 0) { open(MAIL,"|$mailprog -t"); print MAIL "To: $email\n"; print MAIL "From: $sender\n"; print MAIL "Subject: High server load warning notice at server $servername\n"; print MAIL "Your server, $servername, appears to have a high load.\n\n"; print MAIL "The load averages are:\n"; print MAIL "1 minute: $oneminuteave ($oneminuteavepercpu per CPU)\n"; print MAIL "5 minutes: $fiveminuteave ($fiveminuteavepercpu per CPU)\n"; print MAIL "15 minutes: $fifteenminuteave ($fifteenminuteavepercpu per CPU)\n\n"; if (@messages) { print MAIL "Here is what was just recorded as the current load.\n"; print MAIL "If blank, it means you have no current processes with a high load.\n\n"; print MAIL "@messages\n\n"; } if ($includetop eq "Y") { print MAIL "Here is your recent output from top:\n\n"; foreach (@top) { print MAIL "$_\n"; } } close (mail); } } sub sendmailerror { open(MAIL,"|$mailprog -t"); print MAIL "To: $email\n"; print MAIL "From: $sender\n"; print MAIL "Subject: Incorrect reading from TOP output on server $servername\n"; print MAIL "Your server, $servername, appears to have a different output for TOP. The data could not be read properly.\n\n"; print MAIL "Please help me make adjustments for your servers output by issuing the command top in shell and sending the output to me at scripts\@premierwebsitesolutions.com.\n\n"; print MAIL "Also, please forward the following messages to me.\n\n"; print MAIL "-" x 20; print MAIL "\nThe error is:\n$error\n"; print MAIL "PID: $PID\n"; print MAIL "USER: $USER\n"; print MAIL "CPU: $CPU\n"; print MAIL "MEM: $MEM\n"; print MAIL "TIME: $TIME\n"; print MAIL "process line: -$tmp2-\n"; print MAIL "-" x 20; print MAIL "\n\nOnce I have the modifications finished I will let you know.\n\n"; print MAIL "Mike\n"; close (mail); exit; }