Cron does not have its own log file by default. It writes through syslog. Which file your cron logs land in depends on which distro you are on, which init system, and whether anyone has touched the rsyslog config. This is the actual path-by-path reference, plus when you should stop reading log files and start using a managed dashboard.
TL;DR by distro:
- Debian / Ubuntu:
/var/log/syslog(filtered) andjournalctl -u cron. - RHEL / CentOS / Rocky / Fedora:
/var/log/cron(dedicated file). - Alpine, Busybox:
/var/log/messages(or stdout if no syslogd). - macOS:
log show --predicate 'process == "cron"' --last 1h. - systemd-only systems:
journalctl -u cronorjournalctl -u crond.
If you are mid-incident and the log file is silent, see cron job not running: the 8-step debug checklist. For the full troubleshooting decision tree, see the cron troubleshooting hub.
Debian and Ubuntu
The cron daemon on Debian-family distros (Debian, Ubuntu, Linux Mint) writes through syslog. The lines land in /var/log/syslog interleaved with everything else syslog is collecting:
grep CRON /var/log/syslogFor just the last hour:
grep CRON /var/log/syslog | tail -50On modern Ubuntu (20.04+), rsyslog is the default and the file is still /var/log/syslog. On systems where someone disabled rsyslog in favor of systemd-journald only, the file may not exist. In that case use:
journalctl -u cron --since todayjournalctl is the right answer on any Debian/Ubuntu system with systemd. It works even when rsyslog is degraded.
What the line looks like
A typical cron line in /var/log/syslog:
May 24 02:00:01 server CRON[12345]: (root) CMD (/usr/bin/python3 /opt/sync.py)The format is timestamp, hostname, process name with PID, then (user) and CMD (command). If the command produced output and was not redirected, you may also see a separate line from (CRON) with the stdout / stderr the job emitted, sent to syslog priority info.
RHEL, CentOS, Rocky Linux, AlmaLinux, Fedora
Red Hat family distros have a dedicated cron log file at /var/log/cron:
tail -100 /var/log/cronThis is configured in /etc/rsyslog.conf (or /etc/rsyslog.d/) with a line like:
cron.* /var/log/cronLogrotate handles rotation; by default the file rotates weekly and keeps 4 weeks of history.
To follow live:
sudo tail -F /var/log/cronjournalctl -u crond also works on systemd-based RHEL versions (7+).
What the line looks like
May 24 02:00:01 server crond[12345]: (root) CMD (/usr/bin/python3 /opt/sync.py)Same shape as Debian, slightly different process name (crond instead of CRON).
Alpine and Busybox
Alpine ships busybox crond rather than vixie-cron. Logging behavior depends on whether syslogd is running:
# Check if syslog is running on Alpine
rc-status | grep syslogIf syslog is up, cron logs land in /var/log/messages:
grep crond /var/log/messagesIf syslog is down (common in minimal containers), cron writes to stderr, which goes nowhere unless you started crond with -f -L 8 (foreground, log level 8) and redirected output. In production Alpine containers, the usual pattern is to run crond in the foreground as PID 1 with explicit log redirection:
CMD ["crond", "-f", "-d", "8"]The -d 8 enables debug-level output to stderr; Docker then captures stderr and you read it with docker logs <container>.
For more on cron inside containers, see Docker cron jobs.
macOS
macOS still ships cron, though Apple has pushed launchd as the modern alternative since 10.4. If you are using crontab -e on macOS, the cron daemon is logging through the Unified Logging system. The legacy /var/log/system.log was retired in macOS Sierra; the modern command is:
log show --predicate 'process == "cron"' --last 1hFor live tailing:
log stream --predicate 'process == "cron"'If your job uses any GUI-bound API (AppleScript that talks to the desktop session, anything that wants the user keychain), cron may run but the side effects fail silently. That is a launchd use case, not a cron one.
systemd journals (any distro)
On any systemd-based distro, the universal command is:
journalctl -u cron
# or:
journalctl -u crondUseful flags:
--since "1 hour ago"to scope to recent events.-fto follow live.-xto include explanatory messages from the unit.--userif you are looking at user-level systemd timers (not classic cron, but adjacent).
systemd timers are a popular alternative to cron on modern Linux. If your team migrated to *.timer units, journalctl -u myjob.timer and journalctl -u myjob.service are where the logs are.
When the cron log is silent
If grep CRON /var/log/syslog (or the distro equivalent) shows nothing at the expected minute, the daemon did not attempt to run the job. The usual causes:
- The cron daemon is not running. Check with
systemctl status cronorsystemctl status crond. - The crontab entry is in a different user's crontab. Cron will not show up under your user if root owns the entry.
- The crontab syntax is invalid and the daemon refused to load the file. Validate in the free cron expression debugger.
- The server's clock is wrong. Run
timedatectland verify the timezone matches what you wrote in the crontab.
The full debug walkthrough is in cron job not running: the 8-step checklist.
When the log shows the job ran but nothing happened
The log line proves cron called your command. It does not prove your command did anything. Common silent failures:
- The command exited 0 without doing work. Wrong env vars, missing DB connection string, a feature flag that turned off the code path. Compare manual run env vs cron run env: add
env > /tmp/cron-env.txtto the job and diff. - The command's output went to
/dev/null. By default cron emails the crontab owner with any output; many crontabs end in>/dev/null 2>&1to suppress that. Remove the redirect during debugging. - Cron used the wrong shell. Default is
/bin/sh, which isdashon Debian/Ubuntu and lacks bashisms. SetSHELL=/bin/bashat the top of the crontab if your script uses bash features.
When you should not be reading cron logs
You are reading cron logs because something failed and you want to know why. That is fine for a one-off incident. If you find yourself in /var/log/cron more than once a month, the structural answer is to stop reading log files and start using a dashboard that tells you which run failed, when, and what the response was.
Crontap stores the response body, headers, and timing for every fire. You search the dashboard, not grep. Failed runs trigger an email / Slack / Discord / Telegram alert within seconds. The free tier covers one schedule end to end; Pro is a flat annual fee for unlimited schedules at minute cadence.
Stop grepping syslog. External cron with stored run logs and failure alerts. Free forever tier, one schedule. Try Crontap →
FAQ
Where is the cron log file on Ubuntu 24.04?
/var/log/syslog if rsyslog is installed (the default). journalctl -u cron if the system relies on systemd-journald only. Both work; pick whichever is convenient.
Why is there no /var/log/cron on Debian?
Debian-family distros do not configure a dedicated cron log file by default. The cron facility goes to syslog and is filtered into /var/log/syslog along with the rest of the system messages. RHEL-family distros configure a dedicated /var/log/cron instead.
How do I see what a cron job printed to stdout?
By default, cron emails the crontab owner with any stdout/stderr the job produced. If the system does not have a mailer (most containers do not), that mail goes nowhere. The reliable pattern is to redirect explicitly in the crontab:
0 2 * * * /opt/sync.py >> /var/log/sync.log 2>&1Or, if you want the output to be queryable: have the job write to your structured logging service (Datadog, CloudWatch, etc.) and stop relying on cron's mail.
How do I get an alert when a cron job fails?
Either wire stderr into your existing alerting (writes to your log aggregator with a level that pages on-call), or move the cron to a managed external scheduler that includes failure alerts. Crontap retries on 5xx and emails the crontab owner with the response body and status code. Detailed pattern in cron job monitoring.
Are systemd timers better than cron for logging?
For logging, yes. systemd timers run their service unit on a schedule, and the service unit logs to the journal with structured metadata (exit code, duration, stdout, stderr). journalctl -u myjob.service gives you a clean per-run timeline. The trade-off is that systemd timers are more verbose to set up than a crontab line.
Related on Crontap
- Cron job not running: the 8-step debug checklist. The companion incident-mode walkthrough.
- Cron troubleshooting. The hub that aggregates this post plus the other failure-mode pages.
- Cron job monitoring. The service page: failure alerts, run history, dead-man pairing.
- What is a cron job in Linux?. The pillar reference for crontab setup, syntax, and daemon model.
Stop grepping syslog. External cron with stored run logs and failure alerts. Free forever tier, one schedule. Try Crontap →
