#!/usr/bin/perl -w
########################################################
# Load Monitor by Larry Long - larry@djslyde.com       #
# checkload - 4/7 programs in checksuite v2.4          #
#						       #
# This greps the 5 minute load from /proc/loadavg      #
# and if it goes over a certain threshold, it can log  #
# and/or e-mail a notification.                        #
########################################################
use strict;
use Getopt::Std;
use Net::SMTP;

# Options: -h (help) -l (log) -o (output to screen) -e (email)
my %opt;getopts('hlot:e:', \%opt);
usage_info() unless defined @ARGV;
usage_info() if exists $opt{h};

# Localize variables throughout the rest of the program
my($email,$host,$threshold,@ps_data,$plist,@load,$proc,$pid,@note,$notify,$logdate,$logfile,$logsnip,$script,$subject);

# Define variables
$threshold = $opt{t};$threshold = '7' unless defined $opt{t};
$email = $opt{e};$email = 'root' unless defined $opt{e};
$host = `hostname`;
$logfile = "/var/log/checksuite";
$logdate = `date '+%m/%d/%Y %H:%M:%S' `;
$script = " - [checksuite] checkload\n";
$logsnip = "----\n";
$notify = 0;
$subject = "[checksuite] advisory - load average is high on $host";
chomp $host;chomp $logdate;chomp $subject;

# Pull the 5 minute load
open(LOAD5, "/proc/loadavg") or die "Can't open /proc/loadavg!\n";
while(<LOAD5>)
   {
   @load = split(/\s+/, $_);
   if($load[1] >= $threshold)
      {
      push(@note, "Current 5 minute load average is above threshold ($threshold): $load[1]\n\n");
      push(@note, "Possible Contributions:\n");

# Let's single out the processes that are contributing to the load
      open(PSLIST, "ps -elf --no-headers|");
      while(<PSLIST>)
         {
         chop;
         @ps_data = split(/\s+/, $_);
         if($ps_data[5] != 0)
            {
            $ps_data[15] = " " unless defined $ps_data[15];
            $ps_data[16] = " " unless defined $ps_data[16];
            $ps_data[17] = " " unless defined $ps_data[17];
            $ps_data[18] = " " unless defined $ps_data[18];
            $ps_data[19] = " " unless defined $ps_data[19];
            $ps_data[20] = " " unless defined $ps_data[20];
            $ps_data[21] = " " unless defined $ps_data[21];
            push(@note, "pid: $ps_data[9] |cpu time: $ps_data[5] |user: $ps_data[2] |command: $ps_data[14] $ps_data[15] $ps_data[16] $ps_data[17] $ps_data[18] $ps_data[19] $ps_data[20] $ps_data[21]\n");
            }
         }
      close(PSLIST);
      $notify++;
      }
   }
close(LOAD5);

# Define where the output goes
if($notify > 0)
   {
   log_data() if exists $opt{l};
   email_data() if exists $opt{e};
   screen_data() if exists $opt{o};
   }

# Subroutines
sub usage_info
   {
   my $usage = "
Usage: $0 [-h | -lo] [-t <threshold>] [-e <email>]
Options:
-h              display this help
-l              log the output to /var/log/checksuite
-o              force output to screen
-t              sets the threshold for notification
-e              e-mail the output to a specified e-mail address
Where:
<threshold>     threshold value - default is 7
<email>         e-mail address of the recipient of the notification
\n";
   die $usage;
   }

sub log_data
   {
   open(LOG, ">>$logfile") or die "Can't open logfile!\n";
   print LOG $logdate,$script,@note,$logsnip;
   close(LOG);
   }

sub screen_data
   {
   print STDERR @note;
   }

sub email_data
   {
   my $smtp = Net::SMTP->new($host);
   if(! ref($smtp))
      {
      log_die("Cannot connect to SMTP\n");
      }
   $smtp->mail($email);
   $smtp->to($email);
   $smtp->data();
   $smtp->datasend("To: " . $email . "\n");
   $smtp->datasend("From: Checksuite Notification <root\@$host>\n");
   $smtp->datasend("Return-Path: " . $email. "\n");
   $smtp->datasend("Subject: " . $subject . "\n");
   $smtp->datasend("\n");
   $smtp->datasend(@note);
   $smtp->datasend();
   $smtp->quit();
   }
