Friday, April 20, 2012

Alert me by email when some Unix log files became non empty, without having sendmail enabled!

Here's a bash script that does that. Let the server alert you when something's wrong. Probably the tiniest STMP client implementation possible :)

In bold what you need to change to make it work for you.

#!/usr/local/bin/bash
# A script to alert the programmer by email when
# one or more log files in a dir become not empty.
# To be used in a crontab, e.g.:
#
## use /usr/loca/bin/bash to run commands, overriding the default set by cron 
#SHELL=/usr/local/bin/bash
## run once a the end of the day
#0 20 * * *     $HOME/bin/alert_not_empty.sh

dir=/path/to/logs/
files=(file1_log file2_log)

notempty=()
for file in "${files[@]}"; do
  if [ -s "$dir/$file" ]; then
    notempty=( "${notempty[@]}" "$file" )
  fi
done

if [ ${#notempty[@]} -ne 0 ]; then
  notempty=$(printf "%s\n" "${notempty[@]}")

  # You can use mail or mailx, but what if sendmail is disabled for remove
  # delivery? (e.g. for security reasons). Let's help ourselves a bit LOL
  # Use "host -t mx yourispdomain.name" to find out yourispmailserver
  exec 1<>/dev/tcp/gmail-smtp-in.l.google.com/25
  a=$(cat <<mailend yourserver.domain.name
MAIL FROM: <yourusername@yourserver.domain.name>
RCPT TO: <youremail@yourispdomain.name>
DATA
From: yourusername@yourserver.domain.name
To: youremail@yourispdomain.name
Subject: message subject
You have to check the following log files:
 
$notempty
.
QUIT
MAILEND
  )
  
  # Needed to write whole commands in one go.
  IFS='
'

  # This converts a to an indexed array b.
  declare -a b=($a)
  
  for x in "${b[@]}"; do
    # We always sleep after each line, even in data mode.
    # This is slower, but makes the implementation simpler.
    # For slow connections, 1 second may not be enough.
    sleep 5
 
    # Send command. Be sure to use DOS end of lines
    # or some SMTP servers may choke on the commands.
    echo -ne "$x\r\n"
  done
fi

Here's a more advanced versions: it has debugging output, actually reads replies and is much faster when sending the body of the email, since it doesn't sleep after each line has been sent:

function read_reply {
  # DEBUG.
  echo -n "sleeping..."

  # Sleep to make sure a reply has arrived.
  sleep 10

  # DEBUG.
  echo -en "\nread reply..."

  # Read reply.
  read -u 3

  # DEBUG.
  echo

  # DEBUG: print replies.
  echo "$REPLY"
}

# Needed to write whole commands in one go
IFS='
'

# This converts a to an indexed array b!
declare -a b=($a)

# At the beginning, we are in command mode.
# The only other mode is data mode.
cmd=true

# Read server greeting to begin.
read_reply

for x in "${b[@]}"
 do
   # Send command. Be sure to use DOS end of lines.
   echo -ne "$x\r\n" >&3

   # DEBUG: print commands.
   echo "$x"

   [ "$x" = "." ] && cmd=true

   $cmd && read_reply

   [ "$x" = "DATA" ] && cmd=false
 done

No comments: