3 of 3

Processes, Tuning and LogsLesson 3 of 3

Reading logs and keeping the journal

Query the systemd journal by unit, time, priority and boot, write your own entries, and make the journal persistent across reboots.

  • journalctl
  • journalctl -u
  • journalctl -p
  • journalctl -b
  • journalctl --since
  • logger
  • /etc/systemd/journald.conf
  • /var/log/journal
  • journalctl --vacuum-size

45 min5 exercises

After this lesson you can

  • Filter the journal by unit, priority, boot, time range and text, and follow it live.
  • Write test entries with logger and find them again.
  • Make the journal persistent, verify it survived a reboot, and limit its size.

The idea

On RHEL the core log is the systemd journal, written by systemd-journald. It is a binary database that records every unit’s output, the kernel, and anything sent with logger, tagged with fields such as the unit, PID, priority and boot. You query it with journalctl instead of reading text files, which makes precise questions possible.

On systems that also run rsyslog, the traditional text logs exist as well: /var/log/messages (general), /var/log/secure (authentication), /var/log/cron, /var/log/maillog. The journal is always there; check whether the text files exist with ls /var/log before assuming they do.

Filters you will use all the time

QuestionCommand
Messages from one servicejournalctl -u sshd
Only errors and worsejournalctl -p err (levels: emerg alert crit err warning notice info debug)
This boot / previous bootjournalctl -b / journalctl -b -1
A time windowjournalctl --since "1 hour ago" --until "10 min ago"
Follow livejournalctl -f (combine with -u)
Kernel messagesjournalctl -k
Text searchjournalctl -g "denied"
By tag, process or PIDjournalctl -t NAME, _COMM=sudo, _PID=1234
Newest first / last Njournalctl -r, journalctl -n 20
Show all fieldsjournalctl -o verbose

Filters combine: journalctl -u httpd -p err -b --since today is “errors from Apache since this boot that happened today”.

Persistent or not?

By default the journal is stored under /run/log/journal, which is in memory and disappears at reboot. It becomes persistent (kept in /var/log/journal on disk) when that directory exists, or when Storage=persistent is set in /etc/systemd/journald.conf. The exam phrase “preserve the system journal across reboots” means exactly this. Do the directory method and verify with journalctl --list-boots after a reboot.

Try it

journalctl -u sshd -n 3 --no-pager
journalctl -p err -b --no-pager | head -3
Nov 03 08:01:12 rhel10 sshd[842]: Server listening on 0.0.0.0 port 22.
Nov 03 08:01:12 rhel10 sshd[842]: Server listening on :: port 22.
Nov 03 09:32:50 rhel10 sshd[3011]: Accepted publickey for alex from 192.168.122.1 port 51744 ssh2
Nov 03 08:01:20 rhel10 systemd[1]: Failed to start tuned.service - Dynamic System Tuning Daemon.

Write your own entries

logger -t labtest -p user.warning "EX200 lab test"
journalctl -t labtest --no-pager
Nov 03 11:30:05 rhel10 labtest[5120]: EX200 lab test

This is how a cron job from the scheduling lessons can leave evidence, and how you test that logging works.

A time window and live following

journalctl --since "20 min ago" --no-pager | tail -2
journalctl -u httpd -f

-f keeps running and prints new lines; press Ctrl+C to stop. It is the first thing to open in a second terminal while you restart a failing service.

Make it persistent

ls -d /var/log/journal /run/log/journal
ls: cannot access '/var/log/journal': No such file or directory
/run/log/journal

Only the in-memory copy exists. Create the directory and restart the daemon:

sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
sudo journalctl --flush
journalctl --list-boots
IDX BOOT ID                          FIRST ENTRY                 LAST ENTRY
  0 2fbb9b3e0c0a4e1a9d7c5b2e1c6a1f10 Tue 2026-11-03 08:01:05 +03 Tue 2026-11-03 11:35:41 +03

After a reboot a second line appears (with index -1), which proves the old boot was kept. To state the choice in the configuration instead:

[Journal]
Storage=persistent

Keep it from filling the disk

journalctl --disk-usage
sudo journalctl --vacuum-size=100M
Archived and active journals take up 48.0M in the file system.
Vacuuming done, freed 0B of archived journals from /var/log/journal.

A persistent journal otherwise grows until it uses up to 10 % of the file system (and no more than 4 GB). Cap it with SystemMaxUse=200M in the [Journal] section, or remove old entries with --vacuum-time=2weeks, then restart systemd-journald.

Going further

journalctl -o json-pretty produces machine-readable output; -o cat strips everything except the message, handy in scripts. rsyslog rules in /etc/rsyslog.d/*.conf route messages to files by facility and priority (local0.* /var/log/lab.log), and logrotate (config in /etc/logrotate.conf and /etc/logrotate.d/, run daily by a timer) rotates those text files. journalctl --verify checks journal integrity. In RHEL 10 check rpm -q rsyslog before relying on /var/log/messages. Audit messages from SELinux go to /var/log/audit/audit.log, covered in the SELinux skill.

Practice

0 of 5 done

Do these on your own system. They get harder. Check each result, then tick it off.

  1. Warm-up

    Ask the journal a question

    Show the last 10 lines for sshd, then every message of priority err or worse since the current boot, then the kernel messages from this boot.

    Check your result

    Three outputs: unit-specific lines, only error-level lines, and kernel ring-buffer messages.

    Hint

    journalctl -u sshd -n 10, journalctl -p err -b, journalctl -k -b. Add --no-pager for scripts.

    Solution
    journalctl -u sshd -n 10 --no-pager
    journalctl -p err -b --no-pager
    journalctl -k -b --no-pager | tail -5
  2. Practice

    A time window

    Show everything logged in the last 20 minutes, then everything between 09:00 and 10:00 today, then everything from the previous boot.

    Check your result

    The first two outputs cover the stated period only. The third needs more than one boot in the journal.

    Hint

    --since "20 min ago", --since 09:00 --until 10:00, -b -1. journalctl --list-boots shows available boots.

    Solution
    journalctl --since "20 min ago" --no-pager | tail -5
    journalctl --since 09:00 --until 10:00 --no-pager | head
    journalctl --list-boots
    journalctl -b -1 --no-pager | tail -3
  3. Practice

    Log something and find it

    Write the message EX200 lab test into the system log at priority warning with the tag labtest. Find it by the tag, then by text search, then show it with all its fields.

    Check your result

    journalctl -t labtest shows the message. journalctl -g 'EX200 lab' finds it. -o verbose lists fields such as PRIORITY=4 and SYSLOG_IDENTIFIER=labtest.

    Hint

    logger -t labtest -p user.warning "message". -t tag, -p facility.level.

    Solution
    logger -t labtest -p user.warning "EX200 lab test"
    journalctl -t labtest --no-pager
    journalctl -g 'EX200 lab' --no-pager | tail -2
    journalctl -t labtest -o verbose -n 1 --no-pager
  4. Practice

    Make the journal survive a reboot

    Check whether the journal is currently stored on disk or only in memory. Make it persistent without changing any file other than creating a directory, reboot, and show that more than one boot is listed. Then explain how to make the choice explicit in the configuration.

    Check your result

    ls /var/log/journal exists after the change and journalctl --list-boots lists two or more boots after the reboot. /etc/systemd/journald.conf with Storage=persistent does the same explicitly.

    Hint

    Without /var/log/journal, the default Storage=auto keeps the journal in /run/log/journal (memory, lost at reboot). Create the directory and restart systemd-journald.

    Solution
    ls -d /var/log/journal /run/log/journal 2>&1
    sudo mkdir -p /var/log/journal
    sudo systemctl restart systemd-journald
    sudo journalctl --flush
    sudo reboot
    # after the reboot
    journalctl --list-boots
  5. Challenge

    Limit the journal's size

    Show how much disk the journal uses. Reduce it to 100 MB right now, then set a permanent cap of 200 MB in the configuration and apply it. Prove the setting is loaded.

    Check your result

    journalctl --disk-usage reports a size. journalctl --vacuum-size=100M prints how much was removed. SystemMaxUse=200M is in /etc/systemd/journald.conf (or a drop-in), and systemctl show systemd-journald or the service restart accepts it with no error.

    Hint

    --vacuum-size and --vacuum-time clean on demand. SystemMaxUse= in the [Journal] section limits it permanently. Restart systemd-journald after editing.

    Solution
    journalctl --disk-usage
    sudo journalctl --vacuum-size=100M
    sudo mkdir -p /etc/systemd/journald.conf.d
    printf '[Journal]\nSystemMaxUse=200M\n' | sudo tee /etc/systemd/journald.conf.d/size.conf
    sudo systemctl restart systemd-journald
    journalctl --disk-usage