Cron Output and Logging

How to capture and redirect cron job output. Log to file, disable email, redirect stderr, use syslog, and check the cron log for failed jobs.

ZERO UPLOAD · ALL LOCAL
  1. Type or paste a 5-field cron expression into the input (e.g. */15 * * * *).
  2. Use the preset buttons to load a common schedule instantly.
  3. Edit individual fields (MIN, HR, DOM, MON, DOW) — the expression updates live.
  4. Read the SCHEDULE panel for a plain-English description of the pattern.
  5. Choose a timezone and clock format, then read NEXT 5 RUNS for upcoming execution times.

Worked examples for this use case

Add timestamped logging to a cron job

Before
0 3 * * * /opt/backup.sh
After
0 3 * * * /bin/bash -c 'echo "$(date -Iseconds) start" >> /var/log/backup.log; /opt/backup.sh >> /var/log/backup.log 2>&1; echo "$(date -Iseconds) end" >> /var/log/backup.log'

Wrapping in bash -c allows multiple statements for start and end timestamps.

Email on stderr only, log stdout

After
[email protected]
0 3 * * * /opt/backup.sh >> /var/log/backup.log

Redirect stdout to a log file but let stderr reach MAILTO, and errors in stderr trigger the email.

PRESETS

MIN
HR
DOM
MON
DOW
SCHEDULE

NEXT 5 RUNS

    Cron Output and Logging: Capture Stdout, Stderr, and Email

    When a cron job runs, the command still needs somewhere to put its output. Without configuration, stdout and stderr either accumulate in the system mail spool unread, or disappear into /dev/null if the mail system is not configured.1 Neither outcome helps you debug problems. Explicit output redirection is the standard practice: route stdout and stderr to a log file so you can inspect what each run produced.

    Structured logging serves two purposes: confirming that jobs ran successfully, and diagnosing failures after the fact. For long-running or critical jobs, combining file-based logging with a monitoring check on the log gives you the best visibility without relying on email delivery.

    Redirecting stdout and stderr to a log file

    Append >> /path/to/logfile.log 2>&1 to any cron command to capture all output. >> appends rather than overwrites so multiple runs accumulate in the same file. 2>&1 routes stderr to the same file descriptor as stdout. Without the 2>&1, error messages are sent separately (to MAILTO or discarded). Adding a timestamp prefix makes it easy to correlate log lines with scheduled run times: bash -c 'echo "$(date) starting"; /opt/script.sh' >> /var/log/cron/myjob.log 2>&1.

    Naming logs so runs are traceable

    Use a log path that includes the job name and rotate it before the disk fills. A single shared file for many jobs makes failures harder to attribute, while a descriptive name such as /var/log/cron/nightly-backup.log lets you inspect the right run without decoding a generic system log. Including the date in the filename or using logrotate with date-based suffixes ensures that each run's output remains isolated, which simplifies both debugging and long-term retention policies when different jobs have different compliance requirements.

    Resist the urge to pipe everything to /dev/null even for jobs you believe are safe, because a failed run then leaves no evidence and the next failure looks identical to success. A small log file is cheaper to keep than a missed incident is to diagnose, and it also gives you a record of run duration when you timestamp the start and end. Pair the log with a check that alerts when the file stops updating, so a silent stall becomes a visible alarm rather than a quiet gap in the history.

    Controlling email delivery with MAILTO

    Set MAILTO="" at the top of the crontab to suppress email for all jobs below that line.2 Set [email protected] to route output to a specific address. Choosing an empty MAILTO is the right default when you redirect every job to a log file, because unread cron email is one of the most common sources of silent operational neglect.

    Emailing only critical jobs

    Building on this, you can set MAILTO="" globally but override it for a specific critical job by placing a different MAILTO= assignment just before that job line, then resetting it afterward. This selectively emails output only from the jobs where failure notification matters. For example, a billing pipeline that runs nightly might get [email protected] on its line, while a routine cache-refresh job keeps the global empty MAILTO and stays silent unless you inspect its log file directly.

    Reading cron system logs

    On systemd systems, journalctl -u cron or journalctl -u crond shows all cron daemon activity, including job starts, completions, and daemon errors.3 On older systems, /var/log/syslog contains cron entries prefixed with CRON.4 These system logs show whether the daemon attempted to run the job; your own log file shows what the job did when it ran. Consequently, checking both is necessary when debugging a job that appears in system logs as started but produces no application output.

    The distinction between system logs and application logs is important because they answer different questions. System logs answer whether the daemon fired the job on schedule, while application logs answer whether the job itself succeeded or failed once it started. Before you read either one, you can know exactly when a cron job was due to run, so a start entry at the wrong timestamp is as telling as a missing one. When a job produces no output in your application log but the system log shows a start entry, the command ran but failed immediately, and the error is in the command rather than the schedule.

    Rotating log files for frequently running cron jobs

    When a cron job runs every minute or every 5 minutes, the log file grows without bound unless you configure rotation. The logrotate utility handles this automatically on most Linux distributions: add a configuration file in /etc/logrotate.d/ specifying the log path, rotation frequency (daily or weekly), the number of old files to retain, and whether to compress them.5

    Setting up logrotate for a cron log file

    A logrotate configuration for /var/log/myapp-cron.log rotates daily, keeps 7 days of history, compresses old files, and skips rotation if the file is empty or missing. logrotate itself runs from /etc/cron.daily on most distributions, so no additional scheduling is required. Without rotation, a high-frequency cron job writing verbose output can fill the disk in days; with logrotate, you control exactly how much history to retain without manual cleanup.

    Using syslog for cron job output

    For organizations that aggregate logs in a centralized syslog system (rsyslog, journald forwarding, or a cloud logging service), piping cron output through the logger command routes job output into the same log stream as system events.6 The pattern is: 0 3 * * * /opt/backup.sh 2>&1 | /usr/bin/logger -t myapp-backup. Each line of output appears in syslog with the tag myapp-backup, queryable with journalctl -t myapp-backup or searchable in your log aggregation tool.

    This approach avoids per-job log files entirely and makes cron output searchable alongside service logs, kernel messages, and security events. Use the -p flag to set a log priority if your syslog configuration routes messages by severity: -p user.info marks output as informational, while -p user.err marks it as an error.

    When to use this

    Set up output redirection for every cron job at the time of writing, not after a failure occurs. Review cron system logs when a job stops running without explanation. Use structured log files with timestamps for any job that runs frequently enough that you need to distinguish one run's output from another, and before you start digging through logs for a job that never fired, run the expression through a parser first, since a scheduling mistake produces the exact same silence as a logging gap.

    Examples

    Add timestamped logging to a cron job

    Before
    0 3 * * * /opt/backup.sh
    After
    0 3 * * * /bin/bash -c 'echo "$(date -Iseconds) start" >> /var/log/backup.log; /opt/backup.sh >> /var/log/backup.log 2>&1; echo "$(date -Iseconds) end" >> /var/log/backup.log'

    Wrapping in bash -c allows multiple statements for start and end timestamps.

    Email on stderr only, log stdout

    Redirect stdout to a log file but let stderr reach MAILTO, and errors in stderr trigger the email.

    Sources
    1. 1.

      Linux man7, "crontab(5) — Linux manual page," man7.org, accessed June 2026. https://www.man7.org/linux/man-pages/man5/crontab.5.html

    2. 2.

      The Open Group, "crontab — schedule periodic background work," opengroup.org, 2018. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html

    3. 3.

      Free Desktop, "journalctl," freedesktop.org, accessed June 2026. https://freedesktop.org/software/systemd/man/latest/journalctl.html

    4. 4.

      Ubuntu Manpages, "cron(8) — Ubuntu manual page," manpages.ubuntu.com, accessed June 2026. https://manpages.ubuntu.com/manpages/questing/man8/cron.8.html

    5. 5.

      Debian Manpages, "logrotate(8) — Debian manual page," manpages.debian.org, accessed June 2026. https://manpages.debian.org/bookworm/logrotate/logrotate.8.en.html

    6. 6.

      Linux man7, "logger(1) — Linux manual page," man7.org, accessed June 2026. https://www.man7.org/linux/man-pages/man1/logger.1.html

    FAQ