Skip to main content

Monitor server load, disk, CPU and memory with email alerts

A small shell script, run from cron every 5 minutes, that checks four health numbers and emails you when one goes over its limit. It doesn't need an agent or a monitoring server.

What it checks

Check How it is read Default limit
1-minute load average /proc/loadavg 10.00
CPU use vmstat 1 2 (100 minus idle) 98 %
Root disk use df --output=pcent / 98 %
Memory use free (used รท total) 98 %

Each limit can be overridden with an environment variable, so one script works on small and large machines:

LOAD_THRESHOLD=4 DISK_THRESHOLD=90 RECIPIENTS="you@example.com" /usr/local/bin/loadmon.sh

Requirements

awk, df, free, vmstat (procps), bc, logger, a mail command (s-nail) with a working mail relay, and optionally sar (sysstat) to include recent history in the alert email.

Check for every tool at start-up, including bc, so a missing tool fails loudly instead of silently skipping alerts:

for c in awk df free vmstat bc mail logger; do
  command -v "$c" >/dev/null || { logger -t loadmon "missing $c"; exit 1; }
done

Reading the numbers

load=$(cut -d' ' -f1 /proc/loadavg)
cpu=$(vmstat 1 2 | awk 'END {print 100 - $15}')
disk=$(df --output=pcent / | tail -1 | tr -dc '0-9')
mem=$(free | awk '/^Mem:/ {printf "%d", $3 * 100 / $2}')
if (( $(echo "$load > $LOAD_THRESHOLD" | bc -l) )); then ... fi

Avoid parsing top -bn1 for CPU. Its first frame is an average since boot, and its column positions shift.

Schedule it

/etc/cron.d/loadmon:

*/5 * * * * root /usr/local/bin/loadmon.sh >/dev/null 2>&1

Tips

  • Throttle alerts. Write a timestamp file per check (for example /var/lib/loadmon/disk.last), and only email again after an hour. Otherwise a full disk sends 12 emails an hour.
  • Rotate the log. One line every 5 minutes is about 100,000 lines a year. Add /etc/logrotate.d/loadmon.
  • Check more than /. Loop over /var, /home and data volumes too.
  • Use hostname -s in the subject line so you can tell servers apart.