systemd Cheatsheet

journalctl

Use this systemd reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

The Four Flags You Need

Ninety percent of journal use is one of these.

journalctl -u nginx.service          # one unit
journalctl -u nginx -f               # follow, like tail -f
journalctl -u nginx -n 100           # last 100 lines
journalctl -u nginx -b               # this boot only
journalctl -u nginx -e               # jump to the end in the pager
journalctl -xeu nginx                # the one to memorize: catalog + end + unit
FlagEffect
-u, --unit=Filter to a unit. Accepts globs, may repeat
--user-unit=Same for a --user manager unit
-f, --followStream new entries until Ctrl-C
-n, --lines=NLast N entries, default 10. -n all for everything, -n +N for the oldest N
-r, --reverseNewest first
-e, --pager-endOpen the pager at the end. Implies -n 1000
-x, --catalogAdd explanatory text from the message catalog
--no-pagerStraight to stdout, essential in scripts
-q, --quietSuppress the informational header and hints
-o catMessage text only, no timestamps or fields

Time and Boot Windows

journalctl --since "2026-09-14 08:00" --until "2026-09-14 09:30"
journalctl --since "1 hour ago"
journalctl --since yesterday --until today
journalctl --since "-30min"
journalctl -u nginx -S 09:00 -U 17:00      # short forms of --since / --until

Accepted forms are YYYY-MM-DD HH:MM:SS, today, yesterday, tomorrow, now, and relative offsets like -1h, +30min, 2 days ago. Omit the time and 00:00:00 is assumed. Add --utc to print timestamps in UTC.

journalctl --list-boots     # index, boot ID, first and last message
journalctl -b               # current boot, same as -b 0
journalctl -b -1            # the previous boot, where the crash is
journalctl -b -2 -p err     # two boots ago, errors and worse
journalctl -b <boot-id>     # a specific boot by ID
journalctl -k -b -1         # kernel messages from the previous boot

-b -1 is how you diagnose an unclean shutdown, and it only works if the journal is persistent. On a volatile journal there is exactly one boot.

Priority, Kernel, and Grep

journalctl -p err                  # err and worse (0..3)
journalctl -p warning..err         # a range
journalctl -p 3 -b --no-pager
journalctl -k                      # kernel ring buffer, implies -b 0
journalctl -g 'timeout|refused'    # PCRE match on MESSAGE=
journalctl -g TIMEOUT --case-sensitive=true
journalctl --facility=daemon,auth
journalctl -t sshd                 # by SYSLOG_IDENTIFIER
journalctl -T sshd                 # exclude that identifier
LevelName
0emerg
1alert
2crit
3err
4warning
5notice
6info
7debug

-p err means "err and more severe", not "only err". -g is lowercase-insensitive automatically and case sensitive as soon as the pattern contains an uppercase letter.

Field Matches

The journal is structured, so you can filter on any field. Bare FIELD=VALUE arguments are matches, not options.

journalctl _PID=4411
journalctl _COMM=sshd
journalctl _UID=1000
journalctl _SYSTEMD_UNIT=nginx.service
journalctl _EXE=/usr/local/bin/myapp
journalctl _TRANSPORT=kernel
journalctl _SYSTEMD_UNIT=nginx.service _PID=4411          # AND
journalctl _SYSTEMD_UNIT=nginx.service _SYSTEMD_UNIT=php-fpm.service  # OR
journalctl _COMM=sshd + _COMM=sudo                        # explicit OR across fields
journalctl /usr/sbin/sshd                                 # a path is shorthand for _EXE=
journalctl --fields                                       # every field name in the journal
journalctl -F _SYSTEMD_UNIT                               # all values a field takes

Two matches on the same field are ORed. Matches on different fields are ANDed. A bare + separates whole OR groups. Useful fields beyond the above: _HOSTNAME, _CMDLINE, _SYSTEMD_USER_UNIT, _SYSTEMD_CGROUP, _BOOT_ID, _KERNEL_DEVICE, PRIORITY, SYSLOG_IDENTIFIER, CODE_FILE, CODE_LINE, MESSAGE_ID, UNIT, USER_UNIT.

Note the difference between -u nginx and _SYSTEMD_UNIT=nginx.service. The -u form also picks up messages about the unit emitted by systemd itself (UNIT=), plus coredumps attributed to it, which is usually what you want.

Output Formats

journalctl -u nginx -o json-pretty
journalctl -u nginx -o json | jq -r '.MESSAGE'
journalctl -u nginx -o cat            # bare message text
journalctl -u nginx -o short-iso      # ISO 8601 timestamps
journalctl -u nginx -o short-precise  # microsecond timestamps
journalctl -u nginx -o verbose        # every field, human readable
journalctl -u nginx -o short-monotonic
journalctl -o export                  # binary-safe serialization for transport
journalctl --output-fields=MESSAGE,_PID -o json
FormatUse
shortDefault, syslog-like, one line per entry
short-iso, short-iso-preciseSortable and unambiguous timestamps
short-preciseMicrosecond resolution
short-monotonicSeconds since boot, good for boot analysis
catMessage only, for piping into other tools
verboseAll fields, when you are hunting for something to filter on
json, json-seqOne object per line, for jq
json-prettyIndented, for reading
exportJournal export format, for shipping
with-unitLike short-full but shows the unit name

Storage, Size, and Cleanup

journalctl --disk-usage
journalctl --header                      # which files back the current view
sudo journalctl --verify
sudo journalctl --rotate                 # archive the active files first
sudo journalctl --vacuum-time=7d         # drop archived files older than 7 days
sudo journalctl --vacuum-size=500M       # keep total under 500M
sudo journalctl --vacuum-files=5         # keep 5 archived files per journal
sudo journalctl --flush                  # move /run journal into /var

Vacuuming only ever touches archived files, never the active one, so --rotate --vacuum-time=1d is the pair that actually frees space now.

Persistent vs volatile is the difference between having logs after a reboot and not.

Storage= in journald.confJournal lives in
volatile/run/log/journal only, gone on reboot
persistent/var/log/journal, created if missing
auto (default)/var/log/journal if that directory already exists, otherwise volatile
noneNothing stored, forwarding still works

That auto default is the gotcha. On a minimal image the directory does not exist, so -b -1 returns nothing. Create it once:

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

Or be explicit in /etc/systemd/journald.conf.d/00-storage.conf:

[Journal]
Storage=persistent
SystemMaxUse=1G
SystemKeepFree=2G
SystemMaxFileSize=128M
MaxRetentionSec=1month
MaxFileSec=1week
RateLimitIntervalSec=30s
RateLimitBurst=10000
ForwardToSyslog=no

Rate limiting is on by default, so a chatty service gets "Suppressed N messages" instead of every line. Raise RateLimitBurst= or set LogRateLimitIntervalSec=0 on the individual unit rather than disabling it globally.