The systemd journal (journald) is a structured binary logging system that collects messages from the kernel, services, and applications into a single queryable store. Unlike text log files, the journal stores rich metadata with every entry — unit name, PID, UID, priority — making filtering far more powerful.
journalctl is the tool for reading the
journal. Learning it well replaces most grep /var/log/messages
workflows with something faster, more precise, and with full timestamps
including the year.
# Show all journal entries (paginated) journalctl # Show newest entries first journalctl -r # Show last N lines journalctl -n 50 # Follow live (like tail -f) journalctl -f # No pager -- full output to stdout journalctl --no-pager # Current boot only journalctl -b # Kernel messages only (like dmesg) journalctl -k journalctl -k -b # kernel messages this bootjournalctl output format:
# Logs for a specific systemd unit journalctl -u sshd journalctl -u nginx journalctl -u postgresql # Follow a service log live journalctl -u sshd -f # Last 50 lines for a service journalctl -u sshd -n 50 # Multiple units at once journalctl -u nginx -u php-fpm # Since last boot journalctl -u sshd -bjournalctl -u sshd -n 4:
# Since a specific time journalctl --since "2026-04-25 10:00:00" journalctl --since today journalctl --since yesterday journalctl --since "1 hour ago" journalctl --since "2 days ago" # Between two times journalctl --since "2026-04-25 08:00" --until "2026-04-25 09:00" # Previous boot journalctl -b -1 # List all boots journalctl --list-bootsjournalctl --list-boots:
journalctl -b -2 to read logs from two boots ago.
Invaluable when troubleshooting a problem that started after a reboot.
# Filter by priority level journalctl -p err # errors and above journalctl -p warning # warnings and above journalctl -p crit # critical and above journalctl -p 0..3 # emerg through err (range) # Errors since boot -- great morning check journalctl -b -p err # Filter by program/tag journalctl -t sshd journalctl -t sudo journalctl -t myapp # matches logger -t myapp # Filter by UID (all logs from a user's processes) journalctl _UID=1001 # Combine filters journalctl -u sshd -p err --since today journalctl -u nginx -p warning --since "1 hour ago"
# Full timestamps with timezone journalctl -u sshd --output=short-full # ISO 8601 timestamps journalctl -u sshd --output=short-iso # JSON output -- one entry per line (great for scripting) journalctl -u sshd -n 5 -o json journalctl -u sshd -n 5 -o json-pretty # Verbose -- shows ALL metadata fields journalctl -u sshd -n 2 -o verbose # Cat format -- just the message, no metadata journalctl -u sshd -n 10 -o cat # Export for archiving journalctl -u sshd --output=export > sshd-logs.export
journalctl -o json to jq for powerful
filtering and analysis, or feed it to a centralized log system.
By default the journal may only be in memory and lost on reboot. Make it persistent:
# Check current storage sudo journalctl --disk-usage ls /var/log/journal/ 2>/dev/null || echo "No persistent journal" # Enable persistent journal sudo mkdir -p /var/log/journal sudo systemd-tmpfiles --create --prefix /var/log/journal sudo systemctl restart systemd-journald # Verify journalctl --list-boots # should show multiple boots nowKey settings in /etc/systemd/journald.conf:
# Apply journald config changes sudo systemctl restart systemd-journald # Manually vacuum old journal entries sudo journalctl --vacuum-size=200M # keep only 200MB sudo journalctl --vacuum-time=2weeks # keep only last 2 weeks sudo journalctl --vacuum-files=5 # keep only 5 journal files
Storage=auto means the journal is only
persistent if /var/log/journal/ exists. If it doesn't,
logs are lost on reboot. Always verify with
journalctl --list-boots — if you only see one boot,
the journal is not persistent.
# How much disk space is the journal using? sudo journalctl --disk-usage # Where are journal files stored? ls -lh /var/log/journal/*/ ls -lh /run/log/journal/*/ # volatile storage location # Vacuum to reclaim space sudo journalctl --vacuum-size=500M # trim to 500MB total sudo journalctl --vacuum-time=30days # remove entries older than 30 days # Verify after vacuum sudo journalctl --disk-usage # Rotate journal files now (instead of waiting) sudo journalctl --rotate # Verify journald is running sudo systemctl status systemd-journaldjournalctl --disk-usage output:
# Morning health check -- errors since last boot journalctl -b -p err --no-pager # Why did a service fail? journalctl -u myapp -n 50 --no-pager journalctl -u myapp --since "30 minutes ago" # What happened right before a crash? journalctl -b -1 -n 100 --no-pager # last 100 lines of previous boot # Find all sudo commands run today journalctl -t sudo --since today | grep COMMAND # Who logged in via SSH today? journalctl -u sshd --since today | grep "Accepted" # Count errors per service journalctl -p err --since today --no-pager | \ awk '{print $5}' | sed 's/\[.*//' | sort | uniq -c | sort -rn | head -10 # Export last week's logs for a service journalctl -u nginx --since "7 days ago" -o json > nginx-week.json # Search journal like grep journalctl --grep="Failed password" journalctl -u sshd --grep="Failed" --since today
journalctl --grep="pattern" searches only the MESSAGE
field of journal entries. Plain journalctl | grep "pattern"
searches the entire formatted output including timestamps and hostnames.
Use --grep for precision, pipe grep for broader matching.
| Command | What it does |
|---|---|
| journalctl -f | Follow journal live |
| journalctl -b | Current boot only |
| journalctl -b -1 | Previous boot |
| journalctl --list-boots | Show all boot sessions |
| journalctl -u SERVICE | Logs for a specific unit |
| journalctl -u SERVICE -f | Follow a service live |
| journalctl -p err | Errors and above only |
| journalctl -b -p err | Errors this boot (morning check) |
| journalctl --since today | Today's entries |
| journalctl --since "1 hour ago" | Last hour |
| journalctl -o json | JSON output for scripting |
| journalctl --grep="pattern" | Search journal messages |
| journalctl --disk-usage | Journal disk usage |
| journalctl --vacuum-size=500M | Trim journal to 500MB |
| journalctl --vacuum-time=30days | Remove entries older than 30 days |
| Task | Old way | journalctl way |
|---|---|---|
| Service logs | grep sshd /var/log/secure | journalctl -u sshd |
| Live follow | tail -f /var/log/messages | journalctl -f |
| Errors only | grep -i error /var/log/messages | journalctl -p err |
| Time range | grep "Apr 25" /var/log/messages | journalctl --since "2026-04-25" |
| Boot logs | cat /var/log/boot.log | journalctl -b |
| Previous boot | Not easily possible | journalctl -b -1 |
| By PID | grep "\[12345\]" /var/log/messages | journalctl _PID=12345 |