When something breaks at 3 AM, journalctl is the first command you reach for. It queries the systemd journal and lets you filter by service, time, priority, PID, or any combination of these. The structured binary format means you can slice logs in ways that plain text files and grep simply cannot match.
This guide covers every practical journalctl filter you will use in day-to-day troubleshooting and monitoring. Each example was tested on a live Ubuntu 24.04 system with systemd 255. For setting up persistent journal storage and retention limits, see our persistent systemd journal configuration guide.
Tested March 2026 on Ubuntu 24.04 LTS with systemd 255 (255.4-1ubuntu8.1)
View Recent Log Entries
Show the last N log entries with -n. This is your go-to for a quick look at what just happened:
journalctl -n 10 --no-pager
The output shows the most recent 10 entries with timestamp, hostname, process, and message:
Mar 25 15:07:20 ubuntu systemd[1016]: Reached target basic.target - Basic System.
Mar 25 15:07:20 ubuntu systemd[1016]: Reached target default.target - Main User Target.
Mar 25 15:07:20 ubuntu systemd[1016]: Startup finished in 141ms.
Mar 25 15:07:20 ubuntu systemd[1]: Started [email protected] - User Manager for UID 1000.
Mar 25 15:07:20 ubuntu systemd[1]: Started session-1.scope - Session 1 of User ubuntu.
Show entries in reverse order (newest first) with -r:
journalctl -r -n 5 --no-pager
Follow Logs in Real Time
Watch new log entries as they appear, similar to tail -f:
journalctl -f
Combine with a service filter to watch only one service:
journalctl -fu ssh.service
Press Ctrl+C to stop following.
Filter by Service Unit
The -u flag filters logs for a specific systemd service. This is the most common filter for troubleshooting:
journalctl -u ssh.service --no-pager -n 8
The output shows only SSH-related messages:
Mar 25 15:07:18 ubuntu sshd[1009]: Server listening on :: port 22.
Mar 25 15:07:18 ubuntu systemd[1]: Started ssh.service - OpenBSD Secure Shell server.
Mar 25 15:07:18 ubuntu sshd[1010]: Connection closed by 129.222.187.73 port 32744
Mar 25 15:07:20 ubuntu sshd[1011]: Accepted publickey for ubuntu from 129.222.187.73 port 51497 ssh2
Mar 25 15:07:20 ubuntu sshd[1011]: pam_unix(sshd:session): session opened for user ubuntu(uid=1000)
Filter multiple services at once:
journalctl -u ssh.service -u nginx.service --no-pager -n 20
Note: service names vary between distros. Ubuntu 24.04 uses ssh.service while Rocky Linux uses sshd.service. Check your service name with systemctl list-units --type=service.
Filter by Time
Narrow logs to a specific time window with --since and --until. Both accept absolute timestamps and relative expressions.
Logs from the last hour:
journalctl --since "1 hour ago" --no-pager -n 20
Logs from today only:
journalctl --since today --no-pager -n 20
Logs between two specific timestamps:
journalctl --since "2026-03-25 15:06:00" --until "2026-03-25 15:07:30" --no-pager -n 10
The output shows only entries within that 90-second window:
Mar 25 15:07:22 ubuntu sshd[1011]: pam_unix(sshd:session): session closed for user ubuntu
Mar 25 15:07:22 ubuntu systemd-logind[758]: Session 1 logged out. Waiting for processes to exit.
Mar 25 15:07:22 ubuntu systemd[1]: session-1.scope: Deactivated successfully.
Mar 25 15:07:22 ubuntu systemd[1]: session-1.scope: Consumed 1.932s CPU time.
Logs from yesterday:
journalctl --since yesterday --until today --no-pager
Other relative expressions that work: "5 minutes ago", "2 hours ago", "3 days ago", yesterday, today, now.
Filter by Priority Level
Syslog priority levels range from 0 (emergency) to 7 (debug). The -p flag filters by priority, showing all entries at the specified level and above:
journalctl -p err --no-pager
This shows entries at err (3) and above, including crit, alert, and emerg. Available priority names:
| Level | Name | Meaning |
|---|---|---|
| 0 | emerg | System is unusable |
| 1 | alert | Immediate action required |
| 2 | crit | Critical conditions |
| 3 | err | Error conditions |
| 4 | warning | Warning conditions |
| 5 | notice | Normal but significant |
| 6 | info | Informational messages |
| 7 | debug | Debug-level messages |
Filter a specific priority range (e.g., only warnings):
journalctl -p warning..warning --no-pager -n 10
Filter by Boot
With persistent journal storage, you can query logs from previous boots. List all recorded boots:
journalctl --list-boots
Each boot has an index number (0 = current, -1 = previous) and a boot ID:
IDX BOOT ID FIRST ENTRY LAST ENTRY
0 6bbaadfab85347a28818957bb54af405 Wed 2026-03-25 15:06:20 UTC Wed 2026-03-25 15:07:20 UTC
View logs from the current boot:
journalctl -b
View logs from the previous boot:
journalctl -b -1
Filter by Kernel Messages
The -k flag shows only kernel messages (equivalent to dmesg but with timestamps and filtering):
journalctl -k --no-pager -n 5
Kernel messages include hardware detection, driver loading, and filesystem events:
Mar 25 15:06:44 ubuntu kernel: kauditd_printk_skb: 103 callbacks suppressed
Mar 25 15:06:44 ubuntu kernel: loop0: detected capacity change from 0 to 8
Mar 25 15:06:44 ubuntu kernel: audit: type=1400 audit(1774451204.577:115): apparmor="STATUS" operation="profile_replace"
Filter by PID, UID, or GID
Filter logs from a specific process ID:
journalctl _PID=1009 --no-pager -n 5
Filter by user ID (all messages from root):
journalctl _UID=0 --no-pager -n 5
Find the PID of a running service first, then query its logs:
SSHD_PID=$(pgrep -o sshd)
journalctl _PID=$SSHD_PID --no-pager
Filter by executable path (all messages from the sshd binary):
journalctl _EXE=/usr/sbin/sshd --no-pager -n 5
Search with Pattern Matching
The -g flag (or --grep) searches message text using regular expressions. Find all SSH-related entries:
journalctl -g "ssh" --no-pager -n 5
Search for failed login attempts:
journalctl -g "Failed password|authentication failure" --no-pager
Case-insensitive search with --case-sensitive=no:
journalctl -g "error" --case-sensitive=no --no-pager -n 10
Output Formats
Journalctl supports multiple output formats via -o. The format you choose depends on whether you are reading logs manually or feeding them to a script.
| Format | Flag | Use Case |
|---|---|---|
| Default (short) | -o short | Human-readable, syslog style |
| ISO timestamps | -o short-iso | Unambiguous timestamps for log analysis |
| JSON (compact) | -o json | Piping to jq or scripts |
| JSON (pretty) | -o json-pretty | Readable structured data |
| Verbose | -o verbose | All metadata fields for debugging |
| Message only | -o cat | Just the message text, no metadata |
| Export | -o export | Binary export for systemd-journal-remote |
ISO timestamp format for clean log analysis:
journalctl -o short-iso -n 3 --no-pager
2026-03-25T15:07:20+00:00 ubuntu systemd[1016]: Startup finished in 141ms.
2026-03-25T15:07:20+00:00 ubuntu systemd[1]: Started [email protected] - User Manager for UID 1000.
2026-03-25T15:07:20+00:00 ubuntu systemd[1]: Started session-1.scope - Session 1 of User ubuntu.
JSON output with full structured metadata (useful for piping to jq):
journalctl -u ssh.service -n 1 -o json-pretty --no-pager
The JSON output includes every field the journal stores for that entry:
{
"PRIORITY" : "6",
"_UID" : "0",
"_SYSTEMD_UNIT" : "ssh.service",
"_EXE" : "/usr/sbin/sshd",
"_PID" : "1218",
"MESSAGE" : "pam_unix(sshd:session): session opened for user ubuntu(uid=1000)",
"__REALTIME_TIMESTAMP" : "1774451258043395",
"_HOSTNAME" : "test-ubuntu-24-computingforgeeks-com"
}
Verbose format shows all metadata fields for a single entry:
journalctl -u ssh.service -n 1 -o verbose --no-pager
This is the most detailed view available. Each field (PID, UID, executable path, cgroup, boot ID) appears on its own line:
Wed 2026-03-25 15:07:38.042876 UTC
_BOOT_ID=6bbaadfab85347a28818957bb54af405
_MACHINE_ID=c062bd9deb7c533216c9fa60191f76f3
PRIORITY=6
_UID=0
_SYSTEMD_UNIT=ssh.service
_EXE=/usr/sbin/sshd
_PID=1218
_CMDLINE="sshd: ubuntu [priv]"
MESSAGE=pam_unix(sshd:session): session opened for user ubuntu(uid=1000)
Combine Filters
The real power of journalctl comes from combining filters. Each filter narrows the results further.
SSH errors in the last hour:
journalctl -u ssh.service -p err --since "1 hour ago" --no-pager
Kernel messages from the previous boot at warning level or above:
journalctl -k -b -1 -p warning --no-pager
All root user activity from yesterday, in JSON format:
journalctl _UID=0 --since yesterday --until today -o json --no-pager
Follow nginx logs at error priority only:
journalctl -fu nginx.service -p err
Disk Usage and Cleanup
Check how much disk space the journal uses:
journalctl --disk-usage
On a fresh system, this is typically small:
Archived and active journals take up 16.0M in the file system.
Remove journal entries older than 30 days:
sudo journalctl --vacuum-time=30d
Shrink the journal to a maximum size:
sudo journalctl --vacuum-size=500M
For permanent size and retention limits, configure /etc/systemd/journald.conf as described in our persistent journal storage guide.
Quick Reference
All the filtering commands in one table:
| Command | What It Shows |
|---|---|
journalctl -n 20 | Last 20 entries |
journalctl -r | Reverse order (newest first) |
journalctl -f | Follow in real time |
journalctl -u ssh.service | Entries for a service |
journalctl -p err | Errors and above |
journalctl -k | Kernel messages |
journalctl -b | Current boot only |
journalctl -b -1 | Previous boot |
journalctl --since "1 hour ago" | Last hour |
journalctl --since today | Today only |
journalctl _PID=1234 | Specific process |
journalctl _UID=0 | All root activity |
journalctl -g "pattern" | Grep messages |
journalctl -o json-pretty | JSON output |
journalctl -o short-iso | ISO timestamps |
journalctl -o verbose | All metadata fields |
journalctl --disk-usage | Journal disk usage |
journalctl --vacuum-time=30d | Delete entries older than 30 days |
For managing scheduled tasks with systemd timers or controlling services with systemctl, check our other systemd guides.