systemd-journald / journalctl Guide

This guide focuses on practical commands, helpful snippets, and tips & tricks for working with the systemd journal on Linux (RHEL/Alma, Fedora, Debian/Ubuntu, Arch, etc.). It assumes systemd is the init system.


Quick Start: Most-Used Commands

# See everything from the current boot (newest last)
journalctl -b

# Show logs for a systemd unit (service) since last boot
journalctl -u sshd.service -b

# Show only errors for current boot
journalctl -p err -b

# Follow logs (tail) system-wide, like `tail -f`
journalctl -f

# Follow logs for a unit with 200 recent lines, newest first
journalctl -u nginx.service -n 200 -f -r

# Kernel messages from current boot
journalctl -k -b

# Show last 50 entries in reverse, no pager
journalctl -n 50 -r --no-pager

# Grep-like filtering (regex)
journalctl -g 'connection (reset|closed)'

# Between two times
journalctl --since "2025-10-03 14:00" --until "2025-10-03 18:00"

# Human-friendly times
journalctl --since "yesterday" --until "today 06:00"

# Disk usage summary for the journal
journalctl --disk-usage

Priority Filtering

-p filters by syslog priority. Range syntax is allowed (e.g., -p warning..emerg).

Common priorities:

  • emerg=0, alert=1, crit=2, err=3, warning=4, notice=5, info=6, debug=7

Examples:

# Everything warning and worse (<= warning)
journalctl -p warning -b

# Only errors and critical (err..crit) from a unit
journalctl -u httpd.service -p err..crit -b

Unit-Scoped Views

# Specific unit
journalctl -u firewalld.service

# All units matching a glob
journalctl -u "nginx*" -b

# Systemd unit + time window + priority
journalctl -u keepalived.service -S -2h -p warning

Tips:

  • Use systemctl status <unit> as a quick summary; it shows recent journal lines.
  • Services that log to stdout/stderr end up in the journal when StandardOutput=journal or by default on many distros.

Boot Navigation

# List boots with indices and boot IDs
journalctl --list-boots

# Previous boot
journalctl -b -1

# Two boots ago, errors only
journalctl -b -2 -p err

Time Windows

# Since/Until absolute
journalctl --since "2025-10-01 00:00" --until "2025-10-04 23:59"

# Relative
journalctl -S -30m         # last 30 minutes
journalctl -S -1h          # last hour
journalctl -S yesterday    # since yesterday

Notes:

  • --since has a short form -S. --until has -U.
  • Accepts many natural-language forms (today, yesterday, 1 hour ago).

Output Formatting

# Raw message only (great for grep or quick reading)
journalctl -o cat

# JSON (one object per line), good for jq
journalctl -o json

# Pretty JSON
journalctl -o json-pretty

# ISO timestamps
journalctl -o short-iso

# Show explanatory help texts if available (message catalog)
journalctl -x

Handy with jq:

journalctl -u sshd -o json | jq -r '.[\"__REALTIME_TIMESTAMP\", \"MESSAGE\"]'

Grep and Structured Field Matching

Regex search:

journalctl -g 'timeout|reset|unreachable'
# Case-insensitive
journalctl --case-insensitive -g 'failed to start'

Field filters (exact match):

# By systemd unit (same as -u, but explicit field)
journalctl _SYSTEMD_UNIT=sshd.service

# By process executable path
journalctl _EXE=/usr/sbin/sshd

# By command name
journalctl _COMM=sshd

# By UID / GID
journalctl _UID=0
journalctl _GID=0

# By PID
journalctl _PID=1234

# By syslog identifier (traditional applications)
journalctl SYSLOG_IDENTIFIER=cron

Common fields to know:

  • _SYSTEMD_UNIT, _PID, _UID, _GID, _COMM, _EXE, SYSLOG_IDENTIFIER, MESSAGE_ID, PRIORITY, MESSAGE

Tip: Field matches are fast and avoid false positives relative to regex text search.


Following, Paging, and Order

# Follow (tail) with reverse order (newest first), 100 lines
journalctl -n 100 -r -f

# Disable the pager globally for this invocation
journalctl --no-pager

# Start at end of journal
journalctl -e

Cursors: Resume Where You Left Off

# Show last line and print the cursor
journalctl -n 1 --show-cursor

# Tail after a known cursor (e.g., from a previous run)
journalctl --after-cursor "s=deadbeef..."

This is ideal for scripts that need to resume incremental log processing.


Exporting and Archiving

# Save recent service logs to a file with ISO timestamps
journalctl -u nginx -S -2h -o short-iso > nginx-last-2h.log

# Save as JSON for machine processing
journalctl -u sshd -S yesterday -o json > sshd.json

# Convert a journal directory to text
journalctl -D /var/log/journal -o short-iso > all.txt

To convert binary journal files later, just point journalctl -D /path/to/journal.


Disk Usage, Rotation, and Vacuuming

Inspect usage:

journalctl --disk-usage

Rotate and vacuum:

# Force a rotation now (starts a new file)
journalctl --rotate

# Vacuum by keeping total size under 1G
journalctl --vacuum-size=1G

# Vacuum to keep only the last 30 days
journalctl --vacuum-time=30d

# Keep at most 20 files per journal namespace
journalctl --vacuum-files=20

These operations act on the currently selected journal directory (system, runtime, or a -D target).


Persistent Logging (Survives Reboots)

On many distros, journald defaults to volatile storage in /run/log/journal. To make logs persist across reboots:

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
# Or:
sudo journalctl --flush

Verify:

journalctl --disk-usage
test -d /var/log/journal && echo "Persistent OK" || echo "Volatile"

Configuration Basics: /etc/systemd/journald.conf

Create a drop-in to avoid editing the main file:

sudo mkdir -p /etc/systemd/journald.conf.d/
sudo tee /etc/systemd/journald.conf.d/10-persistent-and-limits.conf >/dev/null <<'EOF'
[Journal]
# Storage can be auto, persistent, volatile, none
Storage=persistent

# Space limits for the system journal (persistent)
SystemMaxUse=2G
SystemKeepFree=500M
SystemMaxFileSize=200M

# Space limits for the runtime journal (in /run)
RuntimeMaxUse=256M
RuntimeKeepFree=64M
RuntimeMaxFileSize=64M

# Rate limiting
RateLimitIntervalSec=30s
RateLimitBurst=2000

# Forwarding (optional, if you run rsyslog/syslog-ng)
ForwardToSyslog=yes
EOF

sudo systemctl restart systemd-journald

Notes:

  • Other useful keys: Compress=, Seal=, SyncIntervalSec=, ForwardToKMsg=, ForwardToConsole=, TTYPath=
  • Some options may vary by systemd version. Check man journald.conf on your system.

Access Control

Reading the system journal usually requires root or membership in a group such as systemd-journal or adm (varies by distro).

# Add your user to the group that can read the journal
sudo usermod -aG systemd-journal "$USER"
# Or on Debian/Ubuntu:
sudo usermod -aG adm "$USER"

Log out and back in to apply group changes.


Kernel and Early-Boot Messages

# Kernel-only
journalctl -k

# Early boot (initramfs) often ends up in the journal when dracut/systemd-boot logs are enabled
journalctl -b -0 -k

Coredumps (Bonus)

coredumpctl reads crash dumps stored via journald integration.

# List recent crashes
coredumpctl list

# Show details of the latest crash
coredumpctl info

# Extract a core for analysis
coredumpctl dump > core.latest

# Launch gdb on the most recent coredump for a program
coredumpctl gdb /usr/bin/myapp

If you do not need coredumps, consider setting limits or configuring coredump.conf to restrict disk usage.


Logging From Scripts

Use systemd-cat to send messages to the journal with a custom tag and priority:

# Tag "myscript", default priority info
echo "Job started" | systemd-cat -t myscript

# Tag and priority (debug, info, notice, warning, err, crit, alert, emerg)
echo "An error happened" | systemd-cat -t myscript -p err

# Wrap a command so its stdout/stderr go to the journal
systemd-cat -t backup-job -p info rsync -a /data /backup

Later:

journalctl SYSLOG_IDENTIFIER=myscript -S -1h -o short-iso

Remote Journal (Optional)

If available on your distro, systemd-journal-upload and systemd-journal-remote can ship and receive journals.

Sender (upload client):

sudo systemctl enable --now systemd-journal-upload.service
# Configure /etc/systemd/journal-upload.conf (URL, certs)

Receiver:

sudo systemctl enable --now systemd-journal-remote.socket
# Journals typically under /var/log/journal/remote/

For cross-distro deployments, traditional syslog forwarders (rsyslog, syslog-ng) may be simpler.


Troubleshooting & Verification

# Verify journal files
journalctl --verify

# Show the journal directory currently in use
journalctl -D /var/log/journal --disk-usage
journalctl -D /run/log/journal --disk-usage

# If you changed Storage= and want to move runtime to persistent
journalctl --flush

If journalctl is slow:

  • Prefer structured field filters instead of regex when possible.
  • Restrict by time window or unit.
  • Avoid pretty JSON during heavy scans; use plain text or -o json with downstream tools.

Handy Aliases & Functions (drop into your shell rc)

# Tail a unit
alias jtf='journalctl -f -o short-iso'

junit() {
  # junit nginx [lines]
  local unit="$1"; local n="${2:-200}"
  journalctl -u "$unit" -n "$n" -r --no-pager
}

# Errors from last boot
alias jerr='journalctl -p err -b'

# Grep journal in the last hour
jgrep() {
  # jgrep "pattern" [unit]
  local pat="$1"; local unit="$2"
  if [ -n "$unit" ]; then
    journalctl -u "$unit" -S -1h -g "$pat"
  else
    journalctl -S -1h -g "$pat"
  fi
}

# Export a unit's last boot logs with ISO timestamps
jexport() {
  # jexport nginx /tmp/nginx.log
  local unit="$1"; local out="$2"
  journalctl -u "$unit" -b -o short-iso --no-pager > "$out"
}

Minimal Cheat Sheet

journalctl -b                       # current boot
journalctl --list-boots             # index boots
journalctl -u NAME.service          # by unit
journalctl -p warning               # by priority
journalctl -S -1h                   # last hour
journalctl --since "yesterday"      # human time
journalctl -k                       # kernel only
journalctl -f                       # follow
journalctl -n 200 -r                # last 200, newest first
journalctl -o cat                   # message only
journalctl -g 'regex'               # regex search
journalctl _PID=1234                # by field
journalctl --rotate                 # rotate now
journalctl --vacuum-time=30d        # vacuum retention
journalctl --vacuum-size=1G         # bound size

Man Pages Worth Reading

  • man journalctl
  • man systemd.journal-fields
  • man journald.conf
  • man coredumpctl
  • man systemd-cat