Skip to content

journalctl: Filtering and Formatting systemd Logs

Logs disappeared. Server rebooted, and the familiar less /var/log/syslog returns nothing. On modern distros with systemd, logs are collected by journald and read with journalctl. Without knowing its filters, system debugging turns into guesswork.

Why Logs Disappear After Reboot

By default, journal stores data in /run/log/journal/ — a tmpfs that wipes on reboot. To make logs survive reboots, create the directory:

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal

Then restart systemd-journald:

sudo systemctl restart systemd-journald

Check current location and size:

journalctl --disk-usage
Note

Fresh CentOS/RHEL 8+ and Fedora create /var/log/journal automatically. Debian and Ubuntu typically do not.

Filtering by Unit and Time Range

The most common case — logs for a specific service:

journalctl -u nginx.service
journalctl -u postgresql@main.service

Combine multiple units by repeating the flag:

journalctl -u nginx.service -u php-fpm.service

Time filters are for incident debugging:

# Last hour
journalctl --since "1 hour ago"

# Specific day
journalctl --since "2025-01-15" --until "2025-01-15 23:59:59"

# Last 24 hours
journalctl --since "yesterday"

# From 08:00 to 09:00
journalctl --since "today 08:00" --until "today 09:00"

Night crash? Look at logs from that period, not the entire buffer.

Warning

If a time filter returns empty output, check the timezone. journalctl stores timestamps in UTC, but --since interprets local time.

Filtering by Priority

Log levels match syslog:

LevelNumberDescription
emerg0System unusable
alert1Immediate action required
crit2Critical condition
err3Error
warning4Warning
notice5Normal but significant
info6Informational
debug7Debug-level messages
# Errors and critical only
journalctl -p err -l

# Warnings through errors
journalctl -p warning..err

# Everything from notice upward
journalctl -p notice

The -l flag shows full hostnames instead of truncated ones.

Kernel and Boot Logs

The kernel sends its messages separately. The -k flag replaces dmesg:

# Kernel messages for current boot
journalctl -k

# Kernel messages for previous boot
journalctl -k -b -1

List all boots:

journalctl --list-boots

Output:

-2 5d3c1a9... Mon 2025-01-13 08:00:00 — Mon 2025-01-13 18:00:00
-1 a7b2d8f... Mon 2025-01-13 18:05:00 — Tue 2025-01-14 08:00:00
 0 c9e1f3a... Tue 2025-01-14 08:05:00 — currently running

Select a specific boot:

journalctl -b 5d3c1a9...

For boot analysis, use systemd-analyze:

systemd-analyze blame | head -20
systemd-analyze critical-chain nginx.service

Piping journalctl output to grep loses metadata. Use -g (–grep) instead:

# Search for DB connection failures
journalctl -g "connection.*failed" -u myapp.service

# Authentication errors
journalctl -g "auth.*fail" -p err

The -g flag supports basic regex. For complex conditions, combine with --since:

journalctl -u nginx.service --since "1 hour ago" | grep -E "(timeout|502|503)"

This keeps the unit and time selection intact, then filters by pattern.

Follow Mode (-f)

Analogous to tail -f for journald. Unlike watching a log file, follow works with any filter:

journalctl -u nginx.service -f
journalctl -f -p err
journalctl -u nginx.service -p err -f

Ctrl+C stops follow in a terminal. From scripts, wrap with timeout or send a signal.

Tip

Run -f in a separate tmux/screen pane. If the pane closes, logs keep going to journald — you won’t lose data.

Flags combine with AND: -u nginx -p err shows errors from nginx only. For OR across units, use journal fields:

journalctl --no-pager _SYSTEMD_UNIT=nginx.service OR _SYSTEMD_UNIT=php-fpm.service -p err

Other useful fields:

# By UID
journalctl --no-pager _UID=1000

# By executable
journalctl --no-pager _EXE=/usr/sbin/nginx

# List values seen for a field
journalctl --no-pager -F _SYSTEMD_UNIT

Output Formats

By default, journalctl paginates output. For scripts and piping to jq, you need machine-readable format:

# JSON Lines (jq-friendly)
journalctl -u nginx -n 50 -o json

# JSON with pretty structure
journalctl -u nginx -n 50 -o json-pretty
FlagDescriptionUse Case
-o shortClassic syslogDefault
-o short-isoISO 8601 timestampsSIEM logging
-o short-preciseMillisecond precisionPrecise timing
-o verboseAll fieldsMaximum detail
-o jsonJSON Linesjq, Splunk, ELK
-o catMESSAGE field onlyMinimal output
# Messages only, no metadata — equivalent to tail -f /var/log/app.log
journalctl -u myapp -f -o cat
Tip

-n 100 limits output to the last 100 lines. --no-pager disables pagination for scripts.

Cleanup and Size Management

journald rotates logs by size and time. Configure in /etc/systemd/journald.conf:

[Journal]
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxRetentionSec=30day

Apply without restart:

sudo systemd-tmpfiles --create /etc/tmpfiles.d/journald.conf
sudo killall -USR1 systemd-journald

Free up space manually:

# Show disk usage
journalctl --disk-usage

# Delete logs older than N days
sudo journalctl --vacuum-time=7days

# Delete logs, keeping last N megabytes
sudo journalctl --vacuum-size=200M

# Delete old journal files (not current)
sudo journalctl --vacuum-files=5
Warning

--vacuum-* only removes files exceeding the limit. To free space reliably, increase SystemMaxUse and restart journald.

Common Errors

journalctl: cannot open files — insufficient permissions. Add yourself to the systemd-journal group:

sudo usermod -aG systemd-journal $USER
# re-login

Logs empty after reboot — persistent storage not configured (see first section).

journalctl hangs — huge buffer. Start with -b or limit with --since.

No unit logs — check that the unit actually ran:

systemctl status nginx
journalctl -u nginx --no-pager -n 20

journalctl is built for fast searching. Don’t read logs manually — filter from the start.