How to Read Logs with journalctl
Learn to filter systemd journal logs by unit, time, and priority with journalctl, follow logs live, and manage disk usage on any modern Linux system.
Before you start
- ▸A Linux system running systemd (most distributions since 2015)
- ▸A terminal with sudo access for persistent storage and vacuum operations
- ▸Basic familiarity with the command line
systemd's journal is the central log store on most modern Linux systems. journalctl is the tool that reads it. Unlike the old syslog days where logs were scattered across /var/log/*.log files with varying formats, the journal stores structured, binary entries you can slice any way you need. This guide covers the filters and options you'll reach for daily.
How the Journal Works
The systemd journal is managed by systemd-journald. Logs are written to /run/log/journal/ (volatile, lost on reboot) by default. If /var/log/journal/ exists and is owned correctly, the journal persists across reboots. Check which mode you're in:
journalctl --disk-usage
If it reports a few megabytes, you're likely on volatile storage. To enable persistence:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
Basic Usage
Without arguments, journalctl dumps every entry from the oldest available, piped through a pager (usually less). That's rarely useful on a busy system. Jump straight to the end instead:
journalctl -e
For a fixed number of recent lines, like tail:
journalctl -n 50
Following Logs in Real Time
The -f flag follows new entries as they arrive, exactly like tail -f on a log file:
journalctl -f
You can combine -f with any other filter shown in this guide. For example, follow only SSH:
journalctl -f -u ssh
Filtering by Systemd Unit
The -u flag is the filter you'll use most. Pass any unit name — services, sockets, timers, mounts.
journalctl -u nginx.service
The .service suffix is optional; systemd infers it. To query multiple units at once, repeat the flag:
journalctl -u nginx -u php-fpm
On systems with many containers or instances, glob patterns work too (quote the pattern to stop the shell expanding it):
journalctl -u 'docker-*'
Filtering by Time
--since and --until accept timestamps in several formats. The most practical ones:
# Logs from the last hour
journalctl --since "1 hour ago"
# Logs between two specific times
journalctl --since "2024-06-01 08:00:00" --until "2024-06-01 09:30:00"
# Since last boot only
journalctl -b
The -b flag deserves its own mention. -b 0 is the current boot (default), -b -1 is the previous boot, -b -2 the one before that. List all recorded boots first:
journalctl --list-boots
Output will look roughly like this (it will vary by system):
-3 abc123... Mon 2024-05-27 ...
-2 def456... Tue 2024-05-28 ...
-1 ghi789... Wed 2024-05-29 ...
0 jkl012... Thu 2024-05-30 ...
Then pull logs from a specific boot using its index:
journalctl -b -1
Filtering by Priority
Syslog priority levels run from 0 (emergency) to 7 (debug). journalctl accepts either the number or the name. The -p flag filters to that level and above in severity — meaning lower numbers, which are more critical.
| Number | Name | Meaning |
|---|---|---|
| 0 | emerg | System unusable |
| 1 | alert | Immediate action needed |
| 2 | crit | Critical condition |
| 3 | err | Error condition |
| 4 | warning | Warning condition |
| 5 | notice | Normal but significant |
| 6 | info | Informational |
| 7 | debug | Debug-level messages |
Show only errors and worse across the whole journal:
journalctl -p err
A useful triage command — errors from the current boot only:
journalctl -b -p err
You can also specify a range of priorities with a double-dot syntax:
journalctl -p warning..err
Combining Filters
Filters compose naturally. Show errors from nginx since yesterday:
journalctl -u nginx -p err --since yesterday
Multiple -u flags are OR'd together; other filter types are AND'd. So -u nginx -u php-fpm -p err means: (nginx OR php-fpm) AND priority <= err.
Output Formats
The default output is human-readable. For scripting or shipping logs to another system, use -o:
- json — one JSON object per line, all fields included
- json-pretty — same but formatted for reading
- short-iso — human-readable with ISO 8601 timestamps
- cat — message text only, no metadata
- verbose — every journal field for each entry
# Machine-readable output for a specific unit
journalctl -u nginx -o json | jq '.MESSAGE'
Disk Usage and Housekeeping
Check how much disk space the journal is consuming:
journalctl --disk-usage
To vacuum old entries, use one of three strategies. They all do a dry-run unless you confirm with the actual flag:
# Keep only the last 500 MB
sudo journalctl --vacuum-size=500M
# Keep only logs from the last 2 weeks
sudo journalctl --vacuum-time=2weeks
# Keep only the last 5 boots worth of data
sudo journalctl --vacuum-files=5
To set permanent limits, edit /etc/systemd/journald.conf. The key options are SystemMaxUse, MaxRetentionSec, and MaxFileSec. After editing:
sudo systemctl restart systemd-journald
Verifying Your Setup
Confirm journald is running and the journal is healthy:
systemctl status systemd-journald
journalctl --verify
--verify checks the cryptographic seals (if enabled) and file integrity. Any line beginning with FAIL indicates a corrupted journal file.
Troubleshooting
No logs from before a certain date
You're likely on volatile storage. The journal is cleared on every reboot. Enable persistence as shown in the first section.
Permission denied running journalctl
By default, non-root users can only see their own logs. Add your user to the systemd-journal group for full read access without sudo:
sudo usermod -aG systemd-journal $USER
Log out and back in for the change to take effect.
journalctl output is very slow
This usually means the journal is large and you're scanning without a time or unit filter. Add --since or -u to narrow the search. Also confirm you have a persistent journal on a fast disk — SD cards and slow USB drives make journal reads painful.
Unit name not found
Check the exact unit name with systemctl list-units or systemctl status. Some distros name the same service differently — for example, sshd.service on Fedora/RHEL vs ssh.service on Debian/Ubuntu.
Frequently asked questions
- Why do my logs disappear after every reboot?
- The journal is in volatile mode, storing logs only in /run/log/journal/ which is cleared at shutdown. Create /var/log/journal/ and restart systemd-journald to enable persistent storage.
- Can I read journals from another machine or a rescued system?
- Yes. Use journalctl -D /path/to/journal/directory to point at any journal directory, or --root to specify an alternative filesystem root.
- How do I search journal logs for a specific string?
- Pipe through grep: journalctl -u nginx | grep 'connection refused'. For large time ranges, narrow with --since first to keep it fast.
- What is the difference between journalctl -p err and journalctl -p err..emerg?
- They are equivalent. -p err alone already means 'err and more severe' (emerg, alert, crit, err). The range syntax is just more explicit about the upper bound.
- How do I stop journalctl output from being paged through less?
- Use --no-pager to print directly to stdout, which is also what you want in scripts: journalctl --no-pager -u nginx -n 100.
Related guides
Back Up Linux with Borg or restic
Set up encrypted, deduplicated backups with BorgBackup or restic: local and remote repos, retention pruning, restoring files, and systemd timer scheduling.
How to Check Disk Health with SMART
Learn to use smartctl to read SMART attributes, run drive self-tests, and identify early warning signs of HDD and SSD failure before data loss occurs.
Debug systemd Units that Won't Start
Learn a repeatable workflow to debug systemd services that won't start: status output, journalctl, systemd-analyze verify, and safe override.conf patches.
Linux Server Disaster Recovery Checklist
A practical Linux server disaster recovery checklist: what to back up, RTO/RPO planning, immutable off-site copies, automated restore drills, and verification.