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
| Flag | Effect |
|---|---|
-u, --unit= | Filter to a unit. Accepts globs, may repeat |
--user-unit= | Same for a --user manager unit |
-f, --follow | Stream new entries until Ctrl-C |
-n, --lines=N | Last N entries, default 10. -n all for everything, -n +N for the oldest N |
-r, --reverse | Newest first |
-e, --pager-end | Open the pager at the end. Implies -n 1000 |
-x, --catalog | Add explanatory text from the message catalog |
--no-pager | Straight to stdout, essential in scripts |
-q, --quiet | Suppress the informational header and hints |
-o cat | Message 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
| Level | Name |
|---|---|
| 0 | emerg |
| 1 | alert |
| 2 | crit |
| 3 | err |
| 4 | warning |
| 5 | notice |
| 6 | info |
| 7 | debug |
-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
| Format | Use |
|---|---|
short | Default, syslog-like, one line per entry |
short-iso, short-iso-precise | Sortable and unambiguous timestamps |
short-precise | Microsecond resolution |
short-monotonic | Seconds since boot, good for boot analysis |
cat | Message only, for piping into other tools |
verbose | All fields, when you are hunting for something to filter on |
json, json-seq | One object per line, for jq |
json-pretty | Indented, for reading |
export | Journal export format, for shipping |
with-unit | Like 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.conf | Journal 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 |
none | Nothing 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=noRate 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.