When setting up log monitoring scripts, a common approach is to pipe grep results directly to the mail command:
grep "error" /var/log/syslog | mail -s "Error Alert" admin@example.com
This creates an annoying issue - even when no matching lines are found, an empty email still gets sent. The GNU Mailutils mail command doesn't provide a native option to suppress emails with empty bodies.
The solution involves checking if grep actually found anything before sending the email. Here's a robust approach using shell scripting:
output=$(grep "error" /var/log/syslog)
if [ -n "$output" ]; then
echo "$output" | mail -s "Error Alert" admin@example.com
fi
For those preferring one-liners or different tools, consider these alternatives:
Using grep's -q flag:
grep -q "error" /var/log/syslog && grep "error" /var/log/syslog | mail -s "Error Alert" admin@example.com
Using mailx with body checking:
grep "error" /var/log/syslog | { read body; [ -n "$body" ] && { echo "$body" | mailx -s "Error Alert" admin@example.com; }; }
For production systems, you might want a more comprehensive solution that includes:
#!/bin/bash
LOG_FILE="/var/log/syslog"
SEARCH_TERM="error"
RECIPIENT="admin@example.com"
SUBJECT="Error Alert"
TEMP_FILE=$(mktemp)
grep "$SEARCH_TERM" "$LOG_FILE" > "$TEMP_FILE"
if [ -s "$TEMP_FILE" ]; then
mail -s "$SUBJECT" "$RECIPIENT" < "$TEMP_FILE"
# Optional: add timestamp logging
echo "$(date): Sent alert for '$SEARCH_TERM'" >> /var/log/monitoring.log
fi
rm -f "$TEMP_FILE"
For more complex monitoring scenarios across multiple logs:
#!/bin/bash
LOGS=("/var/log/syslog" "/var/log/nginx/error.log")
RECIPIENT="admin@example.com"
SUBJECT_PREFIX="Alert:"
for log in "${LOGS[@]}"; do
errors=$(grep -i "error\\|warning\\|critical" "$log" 2>/dev/null)
if [ -n "$errors" ]; then
echo "$errors" | mail -s "${SUBJECT_PREFIX} ${log##*/}" "$RECIPIENT"
fi
done
For high-volume log files, these optimizations can help:
- Use
grep -m 10
to limit output to first 10 matches - Add
--line-buffered
flag for real-time monitoring - Consider
logwatch
or similar tools for enterprise environments
When automating log monitoring with command line tools, we often face this scenario:
grep "error" /var/log/app.log | mail -s "Alert" admin@example.com
The issue? This sends an email even when grep finds no matches, resulting in empty notification emails that clutter your inbox.
In production environments, empty notifications create noise and mask real issues. The ideal solution should:
- Only trigger emails when grep finds matches
- Maintain the original matched content
- Work across different Unix-like systems
Method 1: Using if/else in Bash
This is the most straightforward approach:
LOG_CONTENT=$(grep "critical" /var/log/system.log)
if [ -n "$LOG_CONTENT" ]; then
echo "$LOG_CONTENT" | mail -s "System Alert" ops@example.com
fi
Method 2: Using && Operator
A more concise one-liner:
grep "timeout" /var/log/network.log | \
grep -q . && grep "timeout" /var/log/network.log | \
mail -s "Network Issue" netadmin@example.com
Method 3: Using mailx with -E Flag
Some mail clients support empty detection:
grep "segfault" /var/log/app.log | mailx -E -s "Crash Report" dev@example.com
For more robust monitoring, consider this script template:
#!/bin/bash
LOG_FILE="/var/log/application.log"
PATTERN="Exception|Error|Fail"
RECIPIENT="alerts@company.com"
SUBJECT="Application Error Report"
# Check for matches and send email
MATCHES=$(grep -E "$PATTERN" "$LOG_FILE")
if [[ -n "$MATCHES" ]]; then
echo "$MATCHES" | mail -s "$SUBJECT" "$RECIPIENT"
# Optional: Archive the found errors
echo "$(date): $MATCHES" >> /var/log/error_archive.log
fi
Consider these additional improvements:
# Only send if more than 5 errors occur
COUNT=$(grep -c "OOM" /var/log/kernel.log)
if [ "$COUNT" -gt 5 ]; then
grep "OOM" /var/log/kernel.log | mail -s "Memory Crisis" root@localhost
fi
# Add context with surrounding lines
grep -A 2 -B 2 "panic" /var/log/system.log | \
if [ $(wc -l) -gt 0 ]; then \
mail -s "System Panic" admin@example.com; \
fi
For complex monitoring needs, consider:
- swaks: Feature-rich SMTP testing tool
- mutt: Powerful command line MUA with good scripting support
- sendmail: Direct SMTP injection when mail utils aren't available