Read system logs

On Fedora, system logs are managed by systemd's journal and can be read with the journalctl command.

You are staring at a black screen

You run a dnf upgrade, reboot, and the system hangs at a black prompt. Or your laptop wakes from sleep and the network manager refuses to connect. You need to know what failed, but the terminal is empty and the desktop never loads. You are staring at a broken machine and need a way to see what happened behind the scenes.

What's actually happening

Modern Fedora does not scatter logs across dozens of plain-text files. It funnels everything into a single structured database managed by systemd-journald. Think of the journal as a highly indexed spreadsheet. Every row is an event. Every column holds metadata like the exact timestamp, the service that generated it, the process ID, the user ID, and the severity level. The binary format saves disk space and makes searching instantaneous. journalctl is the query interface for that database. It translates your filters into fast lookups instead of scanning megabytes of unstructured text.

The journal captures output from the kernel, systemd units, and any application that writes to the standard syslog socket. It also stores environment variables, control groups, and audit metadata alongside the message text. This structure means you can reconstruct exactly what the system was doing at any given second. You do not need to guess which file a service wrote to. You query the database directly.

Check the service status before you restart it. systemctl status <unit> shows recent log lines and the current state in one view. Always read the output before forcing a restart.

The fix or how-to

Start by opening the full journal. The command is straightforward, but the default behavior catches people off guard. The pager loads everything from the oldest entry to the newest. You want the opposite.

Here is how to load the complete log history and navigate it efficiently.

journalctl -xe
# -x adds explanatory hints for common systemd errors
# -e jumps straight to the end so you see the latest events first
# Press q to exit the pager when you are done reading

The -xe combination is the standard starting point for troubleshooting. The x flag pulls in human-readable context from the system documentation. The e flag skips the thousands of boot messages and lands you at the most recent activity. Most sysadmins type this muscle-memory style when a service refuses to start.

Once you are inside the pager, you can search forward with / and backward with ?. Type a keyword and hit enter. The pager highlights matches and jumps to the first one. Press n for the next match. This works exactly like less or vim search, so you do not need to learn a new interface.

Filtering by service is the next step when you know which component is misbehaving. NetworkManager, sshd, and gdm all generate their own streams of events.

Here is how to isolate logs for a specific systemd unit.

journalctl -u NetworkManager -f
# -u restricts output to the specified unit name
# -f follows the log stream in real time like tail -f
# Useful for watching a service restart or testing a config change

The -u flag accepts partial names. journalctl -u ssh will match sshd.service and ssh.socket. Combine it with -f to watch a service live. This is how you verify a configuration change without constantly refreshing a static file.

Time-based filtering saves you from scrolling through days of irrelevant boot messages. Fedora keeps journals for multiple boot sessions by default, so you can look back at exactly when a problem started.

Here is how to query a specific time window.

journalctl --since "2024-01-15 14:00:00" --until "2024-01-15 15:00:00"
# --since and --until accept ISO 8601 dates or relative strings
# Relative strings like "1 hour ago" or "yesterday" work reliably
# The journal indexes by monotonic and realtime clocks for fast range queries

You can also filter by severity level. The journal uses standard syslog priorities from 0 (emergency) to 7 (debug). Lower numbers mean higher severity.

Here is how to show only errors and critical failures.

journalctl -p err
# -p filters by priority level
# err corresponds to priority 3 and includes crit, alert, and emerg
# Omit the flag to see info and notice messages that explain normal operation

Kernel messages used to live in /var/log/dmesg. Now they flow through the journal alongside user-space events. The -k flag isolates them.

Here is how to view only kernel ring buffer output.

journalctl -k
# -k restricts output to kernel log messages
# Useful for hardware detection, driver loading, and early boot failures
# Combine with -b to see kernel messages from the current boot only

Boot-specific filtering is essential when a system fails to reach the desktop. Each reboot gets a unique boot ID. The -b flag lets you target a specific session.

Here is how to isolate logs from the current or previous boot.

journalctl -b -1
# -b without a number shows the current boot session
# -b -1 shows the previous boot session
# -b -2 shows the session before that, and so on
# Critical for diagnosing crashes that prevented a clean shutdown

Some legacy applications and security tools still write directly to traditional log files. The journal does not capture everything. Audit logs, package manager history, and some third-party daemons bypass systemd-journald entirely.

Here is how to read a traditional log file with proper permissions.

sudo less /var/log/audit/audit.log
# sudo is required because audit logs are owned by root
# less handles large files efficiently without loading them into memory
# Press q to exit and / to search within the file

Check /var/log/dnf.log for package installation history. Check /var/log/boot.log for early startup messages that occur before the journal is fully initialized. Keep these paths in mind when journalctl returns empty results.

By default, Fedora may store the journal only in /run/log/journal, which is a temporary filesystem. Logs disappear when you reboot. Persistence is a one-time setup.

Here is how to enable persistent journal storage across reboots.

sudo mkdir -p /var/log/journal
# The directory must exist before journald will write to disk
# systemd-journald checks for this path on startup
sudo systemctl restart systemd-journald
# Restarts the logging daemon to pick up the new directory
# Logs from the current session are not automatically copied to disk

After the restart, new events write to the persistent directory. Run journalctl --list-boots to verify that past sessions are indexed. You will see a list of boot IDs with timestamps. The journal will now survive reboots and power cycles.

Run journalctl --disk-usage before you start debugging. Know how much space the logs occupy before they fill your root partition.

Verify it worked

Confirm the journal is capturing and persisting data. Check the disk usage and verify that a recent reboot is visible in the history.

Here is how to verify journal persistence and size limits.

journalctl --disk-usage
# Shows how much space the current journal files occupy
# Helps you spot runaway logging before it fills the root partition
journalctl --list-boots
# Lists all boot sessions currently stored in the journal
# A growing list confirms persistence is working correctly

If --list-boots only shows one entry, persistence is not active. Recheck the /var/log/journal directory permissions. The directory must be owned by root:systemd-journal with 2755 permissions. systemd-journald will refuse to write to a directory with incorrect ownership.

Export a clean copy of the logs to verify formatting and completeness.

Here is how to save a filtered journal view to a readable file.

journalctl -u sshd --since "yesterday" > /tmp/sshd-logs.txt
# Redirects formatted journal output to a readable text file
# Safe to grep, edit, or attach to bug reports
# Does not modify the binary journal database on disk

Open the file and scan for Failed, error, or refused. If the output matches what you expect, the journal is functioning correctly. Trust the package manager and the journal daemon. Manual file edits drift, snapshots stay.

Common pitfalls and what the error looks like

The journal fills up the root partition when a service enters a logging loop. You will see disk space warnings or services failing to start because they cannot write temporary files. The journal has built-in size limits, but they only apply to persistent storage. Volatile journals in /run/ can grow until the disk is full.

Check the configuration file in /etc/systemd/journald.conf. Look for SystemMaxUse= and RuntimeMaxUse=. Uncomment them and set reasonable limits like 500M or 1G. Restart the daemon after editing. Never leave these values at zero.

Another common mistake is trying to grep the journal directly. The files in /var/log/journal/ are binary. Running cat or grep on them produces garbage characters and confuses the terminal. Always use journalctl to query the database. If you need to export logs to plain text for analysis, pipe the output to a file.

SELinux denials often look like cryptic permission errors in application logs. They actually appear in the journal with a specific tag. Run journalctl -t setroubleshoot to see human-readable summaries of SELinux blocks. Read those summaries before disabling SELinux entirely. The policy usually points to a missing file context or a misconfigured port.

Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/systemd/journald.conf. Never edit /usr/lib/systemd/journald.conf. Package updates will overwrite changes in /usr/lib/ and silently break your configuration.

If you see Failed to get D-Bus connection: No such file or directory when running journalctl, your system is likely booted in rescue mode or the D-Bus daemon failed to start. Check systemctl status dbus and verify that the system reached multi-user target.

Run journalctl -xe first. Read the actual error before guessing.

When to use this vs alternatives

Use journalctl when you need to troubleshoot service failures, track boot progress, or search across multiple log sources at once. Use dmesg when you only care about raw kernel ring buffer output during early hardware initialization. Use traditional /var/log/ files when dealing with legacy daemons, audit trails, or third-party software that does not integrate with systemd. Use cockpit when you want a web-based log viewer for remote servers without SSH access. Use logrotate when you need to manage plain-text log files that grow indefinitely and require compression or archival.

Where to go next