BugsRadar

Alert when a cron job fails

Cron runs jobs quietly, and a job that fails every night can go unnoticed for weeks. Add one call after the command, and a failure arrives in your Telegram, Discord or Pushover.

You need a BugsRadar project with a channel and the project's API key: see the quick start.

One line in crontab

Add || curl … after the command: curl runs only when the command fails, that is, exits with a code other than 0. The key goes into a variable at the top of the crontab.

crontab -e
BUGSRADAR_KEY=<your project API key>

# Every night at 03:00
0 3 * * * /opt/scripts/import.sh || curl -fsS --max-time 15 -H "X-Api-Key: $BUGSRADAR_KEY" --data-binary "Nightly import failed on $(hostname) with exit code $?" "https://api.bugsradar.com/api/v3/notify?category=cron" > /dev/null

Every job line can end the same way; change the text so that you can tell the jobs apart.

The % sign

Cron treats % in a command as a line break. Write \% if your command has one, for example date +\%F.

A wrapper for all jobs

With many jobs, a small wrapper keeps the crontab readable. It runs the command, and when the command fails, it sends the name of the job, the exit code and the last line of the output. The output still goes to cron's mail or log as before.

/usr/local/bin/cron-alert
#!/usr/bin/env bash
# Usage: cron-alert NAME COMMAND [ARGS...]
name="$1"; shift

output=$("$@" 2>&1)
code=$?

if [ "$code" -ne 0 ]; then
  last=$(printf '%s\n' "$output" | tail -n 1)
  curl -fsS --max-time 15 -H "X-Api-Key: $BUGSRADAR_KEY" \
    --data-binary "$name failed on $(hostname) with exit code $code: $last" \
    "https://api.bugsradar.com/api/v3/notify?category=cron" > /dev/null
fi

printf '%s\n' "$output"
exit "$code"

Make it executable with chmod +x /usr/local/bin/cron-alert and put it in front of each job:

crontab -e
BUGSRADAR_KEY=<your project API key>

0 3 * * *   /usr/local/bin/cron-alert nightly-import /opt/scripts/import.sh
*/15 * * * * /usr/local/bin/cron-alert sync-prices /opt/scripts/sync-prices.sh --all

A job that runs every 15 minutes and keeps failing doesn't flood the chat: the first failure arrives in full, the next ones are counted into summaries. See repeats and grouping.

Test it

false always fails, so this sends a test alert:

Bash
BUGSRADAR_KEY=<your project API key> /usr/local/bin/cron-alert test false