Guides

journalctl: reading, following and filtering the systemd journal

journalctl -u for one service's log, -f to follow it live, --since/--until to narrow by time, -p for severity and -g to search text — with real output for each.

Published ~7 min read

Short answer: journalctl -u NAME shows the log for one systemd service, journalctl -u NAME -f follows it live, and journalctl -u NAME --since today narrows it by time. Without -u it prints the whole system journal — every service, the kernel, logins, all of it — oldest first unless you add -r.

TaskCommand
Logs for one servicejournalctl -u nginx
Follow it live (like tail -f)journalctl -u nginx -f
Last N linesjournalctl -u nginx -n 50
Since a timejournalctl -u nginx --since "2026-10-14 09:00"
Since relative timejournalctl -u nginx --since "1 hour ago"
Newest firstjournalctl -u nginx -r
Today onlyjournalctl -u nginx --since today
This boot onlyjournalctl -b
A previous bootjournalctl -b -1
Search the message textjournalctl -u nginx -g "error"
Errors and worse, any unitjournalctl -p err
Kernel messages (dmesg)journalctl -k
Disk space the journal usesjournalctl --disk-usage
Shrink the journaljournalctl --vacuum-size=200M

journalctl -u: the log for one service

Linux
journalctl -u nginx
Example output
Oct 14 08:02:11 vmheaven systemd[1]: Starting nginx.service - A high performance web server...
Oct 14 08:02:11 vmheaven systemd[1]: Started nginx.service - A high performance web server...
Oct 14 11:40:02 vmheaven systemd[1]: Reloading nginx.service - A high performance web server...
Oct 14 11:40:02 vmheaven systemd[1]: Reloaded nginx.service - A high performance web server...

-u takes the unit name with or without .service; both journalctl -u nginx and journalctl -u nginx.service work. It opens in a pager (q to quit, arrow keys or /text to search inside it), so add --no-pager when piping the output into another command or a log file.

Several units, or a pattern

Linux
journalctl -u nginx -u php8.2-fpm
journalctl -u "ssh*"

Repeat -u to combine logs from several services in time order — useful when a request passes through nginx and then PHP-FPM and you want to see both sides of one failure together. The glob form matches every unit whose name starts with ssh.

Watching logs live: -f

Linux
journalctl -u myapp -f

Behaves like tail -f: it prints new lines as they arrive and keeps running until you press Ctrl+C. Reload or restart the service in a second terminal while this runs to watch it start up, or reproduce a bug while it is open to catch the exact moment it fails.

Narrowing by time: --since and --until

Linux
journalctl -u myapp --since "2026-10-14 09:00:00"
journalctl -u myapp --since "1 hour ago"
journalctl -u myapp --since today
journalctl -u myapp --since yesterday --until today
journalctl -u myapp --since "-15min"

--since and --until accept an absolute timestamp, the words today, yesterday and now, or a relative offset like -15min or "2 days ago". Times are read in the system’s local timezone (timedatectl shows it); add --utc to both the filter and the printed timestamps to work in UTC regardless.

Filtering by severity: -p

Linux
journalctl -p err                 # error and worse, every unit
journalctl -u myapp -p warning    # warning and worse, one unit
journalctl -p 3                   # the same as "err" by its syslog number
NameNumberMeaning
emerg0System is unusable
alert1Action must be taken immediately
crit2Critical condition
err3Error
warning4Warning
notice5Normal but significant
info6Informational (most routine log lines)
debug7Debug-level detail

A level includes everything more severe than itself: -p warning shows warnings, errors, critical and emergency lines, never plain info noise. This only filters on the priority the program itself attached to the line; a program that logs its own errors at info (many do) is invisible to -p err and needs -g on the text instead.

Searching message text: -g

Linux
journalctl -u myapp -g "connection refused"
journalctl -u myapp -g "error|fail" --case-sensitive=false

-g takes a regular expression and matches it against the message field only, which is usually faster and cleaner than piping into grep yourself, and still works when the output format changes. It needs journalctl built with PCRE2 support, which every current Debian, Ubuntu, Rocky and Fedora package has.

journalctl -b: this boot, or a previous one

Linux
journalctl --list-boots
journalctl -b          # current boot
journalctl -b -1       # the boot before this one
journalctl -b -1 -n 60 # its last 60 lines, e.g. to see why it ended
Example output of --list-boots
IDX BOOT ID                          FIRST ENTRY                 LAST ENTRY
 -1 4b9e…a21f                         Tue 2026-10-13 02:11:04 UTC  Tue 2026-10-14 06:58:02 UTC
  0 7c3d…e908                         Tue 2026-10-14 06:58:19 UTC  Tue 2026-10-14 11:42:10 UTC

This is the fastest way to tell why a server rebooted: an orderly shutdown logs a reason at the end of the old boot; a crash or a hard reset just stops, with nothing after the last line. The full walkthrough is in why does my VPS keep rebooting.

journalctl -k: kernel messages

Linux
journalctl -k            # same information dmesg shows, with timestamps and persistence
journalctl -k -b -1      # the kernel's own messages from the previous boot

Unlike the plain dmesg buffer, this survives a reboot as long as the journal itself is persistent (below), which matters for catching an OOM kill or a disk error from before the crash.

Output formats: -o

Linux
journalctl -u myapp -o json-pretty -n 1
journalctl -u myapp -o cat         # message text only, no timestamp or unit prefix
journalctl -u myapp -o short-iso   # ISO 8601 timestamps instead of the default layout

json and json-pretty are the ones to reach for in a script that parses the output, since every field (priority, unit, PID, the raw message) comes back as a named key instead of a line you have to split yourself.

Journal size and vacuuming

Linux
journalctl --disk-usage
sudo journalctl --vacuum-size=200M
sudo journalctl --vacuum-time=2weeks
sudo journalctl --vacuum-files=5

The journal rotates and trims itself based on SystemMaxUse= in /etc/systemd/journald.conf (10% of the filesystem by default, capped at 4 GiB on most setups), but a server that is tight on disk right now does not want to wait for that: the three --vacuum-* flags above free space immediately, by size, by age, or down to a number of files. Checking disk usage covers the rest of what fills a server’s disk besides logs.

Is the journal even kept across reboots?

Linux
ls -la /var/log/journal           # exists and has files: persistent
cat /etc/systemd/journald.conf | grep -i storage

Debian and Ubuntu server images create /var/log/journal and keep logs across reboots by default; a minimal container or cloud image sometimes does not, in which case journalctl -b -1 has nothing to show. Create the directory and restart the logging service to turn it on:

turn on persistent logging
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

journalctl vs /var/log/syslog

Debian 12 and newer install no rsyslog by default, so there is no /var/log/syslog at all and journalctl is the only log on the system. Ubuntu still ships rsyslog, which writes the same events to both /var/log/syslog and the journal, so either works there; journalctl’s advantage is the structured fields (-u, -p, -g, boots) rather than a plain-text file you grep by hand. Rocky Linux and AlmaLinux behave like Ubuntu: rsyslog and the journal side by side.

journalctl for cron and systemd timers

Debian · Ubuntu
journalctl -u cron --since today
Rocky · AlmaLinux
journalctl -u crond --since today

This is the log for whether cron started a job, not what the job printed, which is exactly where people get stuck chasing a cron job that seems to do nothing — cron job not running walks through the rest. A job scheduled with a systemd timer logs under its own service name instead, with the usual journalctl -u myapp.service.

Frequently asked

How do I see the log for just one service?

journalctl -u SERVICE, with or without the .service suffix. Repeat -u to combine several services in one time-ordered view, useful when a request passes through more than one of them, such as nginx and PHP-FPM.

How do I follow logs live, like tail -f?

journalctl -u SERVICE -f. It prints new lines as they arrive and keeps running until you press Ctrl+C — restart the service in a second terminal to watch it come up, or reproduce a problem while it runs to catch the exact moment it happens.

How do I see logs from before the last reboot?

journalctl --list-boots shows every recorded boot by index, and journalctl -b -1 shows the one before the current boot (-b -2 the one before that, and so on) — provided the journal is set to persist across reboots, which Debian and Ubuntu server images do by default.

How do I filter journalctl by how serious an entry is?

journalctl -p err shows error-level entries and anything more severe (critical, alert, emergency) across every unit; add -u SERVICE to limit it to one. This only works for log lines the program itself tagged at that priority — a program that logs its own failures as plain info needs journalctl -g "text" instead.

Related articles

All guides