1. Overview

The cron command-line tool is a job scheduler on Linux operating systems.

In this tutorial, we’ll explore how to check cron jobs’ logs.

2. Introduction to the Problem

Linux’s cron job is a convenient feature as it allows us to automate tasks. In addition, the cron jobs automatically run in the background on time and reduce the repetitive work we need to do.

However, on the other hand, since the jobs run in the background, it’s not that straightforward for us to know the information about job executions, such as whether the jobs started as expected, whether they ran smoothly, or if some jobs raised any error during their run, and so on.

Therefore, checking cron jobs’ logs is important to obtain that information.

Linux is an open system. Usually, there are various applications to achieve the same functionality. For example, there are many cron implementations. Further, different cron implementations may log differently.

Additionally, Linux systems may use various logging systems.

Therefore, checking the cron jobs log depends on the cron implementation and the logging system installed on the system.

In this tutorial, we’ll address how to check cron jobs’ logs based on two widely used cron implementations and two major logging systems:

Next, let’s create a simple cron job as an example for testing.

3. Creating a Cron Job

First, let’s create a simple shell script:

$ cat myJob.sh 
#!/bin/bash
echo "[INFO] $(date) Hello there from the cron job!"
echo "[INFO] $(date) Let's list some files:"
ls /not-existing-dir

As we can see, the myJob.sh script outputs some information and executes the ls command on a non-existing directory. If we run the script, we’ll see the output in STDOUT and STDERR:

$ ./myJob.sh 
[INFO] Fri Sep  2 08:48:25 PM CEST 2022 Hello there from the cron job!
[INFO] Fri Sep  2 08:48:25 PM CEST 2022 Let's list some files:
ls: cannot access '/not-existing-dir': No such file or directory

Now, assuming our system already has cron implementation installed, let’s create a cron job to invoke our myJob.sh script. To create a cron job, we can execute crontab -e and add one line in this format:

<Cron_Expression> Full_Path_Command

Let’s say we want our script to be executed every minute. So, we add this line in the crontab:

 * * * * * /home/kent/cronTest/myJob.sh

After saving and exiting the crontab editor, the cron job is created. We can confirm this by executing crontab -l:

$ crontab -l
 * * * * * /home/kent/cronTest/myJob.sh

Next, let’s check this job’s log on different Linux systems.

For simplicity, we’ll use the same script and keep the same directory structure on Ubuntu and Archlinux.

4. Ubuntu Example – Vixie Cron and Syslog

Ubuntu is a widespread Linux distribution. Vixie cron is used in most Linux distributions and it’s the default cron implementation on Ubuntu.

Also, Ubuntu has installed syslog as the message logging solution. Nowadays, most modern distributions, including Ubuntu, use systemd to configure and manage services.

Therefore, the systemd journal is available on Ubuntu too.

4.1. Checking When the Jobs Started

As Ubuntu uses Syslog, we can see all cron job logs in the /var/log/syslog file. It’s worth mentioning that we need superuser permission to read syslog.

Of course, the file contains all the logs from different applications and modules. We can use the grep command to filter the logs:

$ sudo grep 'CRON' /var/log/syslog
...
Sep  2 21:08:01 AK-Pi CRON[15173]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep  2 21:08:01 AK-Pi CRON[15172]: (CRON) info (No MTA installed, discarding output)
Sep  2 21:09:01 AK-Pi CRON[15318]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep  2 21:09:01 AK-Pi CRON[15317]: (CRON) info (No MTA installed, discarding output)
Sep  2 21:10:01 AK-Pi CRON[15506]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep  2 21:10:01 AK-Pi CRON[15504]: (CRON) info (No MTA installed, discarding output)
Sep  2 21:11:01 AK-Pi CRON[15681]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep  2 21:11:01 AK-Pi CRON[15680]: (CRON) info (No MTA installed, discarding output)

Good, as we wished, our myJob.sh starts every minute. So let’s skip the log entries with the message “No MTA installed, discarding output” for now. We’ll talk about it later.

Since systemd is also available on Ubuntu, *we can use the journalctl -u cron.service command to list all logs of the cron.service unit:*

...
Sep 02 21:17:01 AK-Pi CRON[16770]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep 02 21:17:01 AK-Pi CRON[16769]: (CRON) info (No MTA installed, discarding output)
...
Sep 02 21:18:01 AK-Pi CRON[16959]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep 02 21:18:01 AK-Pi CRON[16957]: (CRON) info (No MTA installed, discarding output)
...
Sep 02 21:19:01 AK-Pi CRON[17131]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep 02 21:19:01 AK-Pi CRON[17130]: (CRON) info (No MTA installed, discarding output)
...

4.2. Checking Job Executions’ Log

We’ve learned how to check if cron jobs have started by checking Syslog. However, we don’t know if the job ran successfully. For example, we may want to check the job’s output or error messages.

But this information is not in the syslog file. So now, it’s time to discuss the “No MTA installed, discarding output” log message.

By default, Linux uses mail for sending notifications to the user. Vixie cron also follows this notification rule. So, if the cron job generated some output during its execution, Vixie cron sends the user the output in mail.

Most Linux distributions have a mail service installed, including an MTA (Mail Transfer Agent). But, Ubuntu doesn’t. That’s why we see that log message.

Of course, we can install and configure the mail service on Linux. However, for simplicity, we won’t cover that in this tutorial. Instead, we can ask the cron job to redirect STDOUT and STDERR to a specified log file.

To achieve that, we can modify the crontab entry with crontab -e and add the redirection:

* * * * * /home/kent/cronTest/myJob.sh >> /home/kent/cronTest/myJob.log 2>&1

The 2>&1 redirection at the very end redirects STDERR to STDOUT so that STDERR is also logged in the file.

After a few minutes, if we check the /home/kent/cronTest/myJob.log file, we can see the detailed job execution output:

$ cat myJob.log 
[INFO] Fri 02 Sep 2022 09:42:01 PM CEST Hello there from the cron job!
[INFO] Fri 02 Sep 2022 09:42:01 PM CEST Let's list some files:
ls: cannot access '/not-existing-dir': No such file or directory
[INFO] Fri 02 Sep 2022 09:43:02 PM CEST Hello there from the cron job!
[INFO] Fri 02 Sep 2022 09:43:02 PM CEST Let's list some files:
ls: cannot access '/not-existing-dir': No such file or directory
[INFO] Fri 02 Sep 2022 09:44:01 PM CEST Hello there from the cron job!
[INFO] Fri 02 Sep 2022 09:44:01 PM CEST Let's list some files:
ls: cannot access '/not-existing-dir': No such file or directory
...

In this way, the job logs are stored in the custom file. So it’s pretty easy to obtain the details of the job execution.

5. Archlinux Example – Cronie and Systemd’s Journal

Archlinux is another popular lightweight Linux distribution. Like most other modern Linux distributions, Archlinux uses systemd to manage services. But Syslog isn’t installed by default, as systemd‘s logging system (journal) does a great job.

As Archlinux’s principle is KISS (keep it simple, stupid), no cron implementation is pre-installed. Therefore, let’s install cronie, a fork from Vixie cron with some enhancements, to see how cronie logs jobs.

We can use a similar journal command to check the cronie.service unit’s logs:

$ journalctl -u cronie.service
...
Sep 02 22:16:01 lhind.hp.g5 CROND[1960553]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep 02 22:16:01 lhind.hp.g5 CROND[1960552]: (kent) CMDOUT ([INFO] Fri Sep  2 10:16:01 PM CEST 2022 Hello there from the cron job!)
Sep 02 22:16:01 lhind.hp.g5 CROND[1960552]: (kent) CMDOUT ([INFO] Fri Sep  2 10:16:01 PM CEST 2022 Let's list some files:)
Sep 02 22:16:01 lhind.hp.g5 CROND[1960552]: (kent) CMDOUT (ls: cannot access '/not-existing-dir': No such file or directory)
Sep 02 22:16:01 lhind.hp.g5 CROND[1960552]: (kent) CMDEND (/home/kent/cronTest/myJob.sh)
Sep 02 22:17:01 lhind.hp.g5 CROND[1960743]: (kent) CMD (/home/kent/cronTest/myJob.sh)
Sep 02 22:17:01 lhind.hp.g5 CROND[1960742]: (kent) CMDOUT ([INFO] Fri Sep  2 10:17:01 PM CEST 2022 Hello there from the cron job!)
Sep 02 22:17:01 lhind.hp.g5 CROND[1960742]: (kent) CMDOUT ([INFO] Fri Sep  2 10:17:01 PM CEST 2022 Let's list some files:)
Sep 02 22:17:01 lhind.hp.g5 CROND[1960742]: (kent) CMDOUT (ls: cannot access '/not-existing-dir': No such file or directory)
Sep 02 22:17:01 lhind.hp.g5 CROND[1960742]: (kent) CMDEND (/home/kent/cronTest/myJob.sh)

As the output above shows, unlike Vixie cron, cronie logs the job’s start time and the STDOUT and STDERR output during each execution. Of course, cronie supports sending the user job output via emails too. But storing the output in the journal is more straightforward.

We have set up only a straightforward cron job for simplicity. Imagine that we have many cron jobs, which might run in parallel. Thus, all jobs’ logs will be interleaved in the journal. In this case, we may get lost in a sea of logs if we only want to check the logs of a specific job.

We can apply the redirection approach we saw earlier to solve it. For example, we can change the job entries in crontab :

* * * * * /home/kent/cronTest/myJob.sh >> /home/kent/cronTest/myJob.log 2>&1
* * * * * /home/kent/cronTest/job2.sh >> /home/kent/cronTest/job2.log 2>&1
* * * * * /.../job3.sh >> /.../job3.log 2>&1
...

Then, each job has its own log file.

6. Conclusion

In this article, we’ve explored how to check the cron jobs’ logs through examples. We discussed two common cron implementations and two different logging systems*.*