Report this

What is the reason for this report?

How To Use journalctl to View and Manipulate systemd Logs on Linux

Updated on July 30, 2025
English
How To Use journalctl to View and Manipulate systemd Logs on Linux

Introduction to systemd Journal and journalctl Logging

Some of the most compelling advantages of systemd are those involved with process and system logging. When using other tools, logs are usually dispersed throughout the system, handled by different daemons and processes, and can be fairly difficult to interpret when they span multiple applications. systemd attempts to address these issues by providing a centralized management solution for logging all kernel and userland processes. The system that collects and manages these logs is known as the journal.

The journal is implemented with the journald daemon, which handles all of the messages produced by the kernel, initrd, services, etc. In this guide, we will discuss how to use the journalctl utility, which can be used to access and manipulate the data held within the journal.

In this article, you’ll learn how to use the journalctl command-line tool to access and filter log data from the systemd journal. We’ll cover how to view logs from specific boots or time ranges, filter by system units, users, or priority levels, and output logs in formats like JSON for integration with other tools. You’ll also learn how to monitor real-time events, manage disk usage, configure persistent logging, and resolve common issues such as missing logs or permission errors. Whether you’re debugging a failing service or setting up centralized log collection, journalctl offers the flexibility and precision to streamline your workflow.

Key Takeaways

  • Centralized Logging with systemd: The systemd journal provides a unified logging system that captures messages from the kernel, services, and user applications in one centralized, indexed log.

  • Powerful Filtering with journalctl: The journalctl command allows you to filter logs by boot sessions, time ranges, systemd units, process IDs, user IDs, group IDs, and more, making it easy to pinpoint relevant events.

  • Flexible Time-Based Queries: You can retrieve logs from specific time windows using options like --since, --until, or relative expressions like "1 hour ago" or "yesterday".

  • Output Format Customization: Logs can be displayed in various formats such as plain text, JSON, and verbose mode, making it easier to integrate with external tools or parse for analysis.

  • Real-Time Monitoring: Using journalctl -f, you can follow log messages live as they are written, similar to tail -f, which is useful for monitoring system activity or service behavior in real time.

  • Persistent vs. Volatile Logging: By default, logs may be stored in memory and lost on reboot. You can enable persistent logging by creating /var/log/journal and configuring journald.conf accordingly.

  • Disk Usage and Log Retention: The journal’s storage footprint can be managed with commands like --disk-usage, --vacuum-size, and --vacuum-time, as well as configuration options to control maximum size and retention.

  • Troubleshooting with Context: journalctl simplifies service debugging by aggregating logs across boots and units, making it easier to identify failures, track SSH access, and investigate issues with detailed context.

How the systemd Journal Works and Why It Matters

One of the impetuses behind the systemd journal is to centralize the management of logs regardless of where the messages are originating. Since much of the boot process and service management is handled by the systemd process, it makes sense to standardize the way that logs are collected and accessed. The journald daemon collects data from all available sources and stores it in a binary format for easy and dynamic manipulation.

This gives us a number of significant advantages. By interacting with the data using a single utility, administrators are able to dynamically display log data according to their needs. This can be as simple as viewing the boot data from three boots ago, or combining the log entries sequentially from two related services to debug a communication issue.

Storing the log data in a binary format also means that the data can be displayed in arbitrary output formats depending on what you need at the moment. For instance, for daily log management you may be used to viewing the logs in the standard syslog format, but if you decide to graph service interruptions later on, you can output each entry as a JSON object to make it consumable to your graphing service. Since the data is not written to disk in plain text, no conversion is needed when you need a different on-demand format.

The systemd journal can either be used with an existing syslog implementation, or it can replace the syslog functionality, depending on your needs. While the systemd journal will cover most administrator’s logging needs, it can also complement existing logging mechanisms. For instance, you may have a centralized syslog server that you use to compile data from multiple servers, but you also may wish to interleave the logs from multiple services on a single system with the systemd journal. You can do both of these by combining these technologies.

How to Set the Correct System Time with timedatectl

One of the benefits of using a binary journal for logging is the ability to view log records in UTC or local time at will. By default, systemd will display results in local time.

Because of this, before we get started with the journal, we will make sure the timezone is set up correctly. The systemd suite actually comes with a tool called timedatectl that can help with this.

First, see what timezones are available with the list-timezones option:

  1. timedatectl list-timezones

This will list the timezones available on your system. When you find the one that matches the location of your server, you can set it by using the set-timezone option:

  1. sudo timedatectl set-timezone zone

To ensure that your machine is using the correct time now, use the timedatectl command alone, or with the status option. The display will be the same:

  1. timedatectl status
Output
Local time: Fri 2021-07-09 14:44:30 EDT Universal time: Fri 2021-07-09 18:44:30 UTC RTC time: Fri 2021-07-09 18:44:31 Time zone: America/New_York (EDT, -0400) System clock synchronized: yes NTP service: active RTC in local TZ: no

The first line should display the correct time.

How to View Logs with journalctl

To see the logs that the journald daemon has collected, use the journalctl command.

When used alone, every journal entry that is in the system will be displayed within a pager (usually less) for you to browse. The oldest entries will be up top:

  1. journalctl
Output
-- Logs begin at Tue 2015-02-03 21:48:52 UTC, end at Tue 2015-02-03 22:29:38 UTC. -- Feb 03 21:48:52 localhost.localdomain systemd-journal[243]: Runtime journal is using 6.2M (max allowed 49. Feb 03 21:48:52 localhost.localdomain systemd-journal[243]: Runtime journal is using 6.2M (max allowed 49. Feb 03 21:48:52 localhost.localdomain systemd-journald[139]: Received SIGTERM from PID 1 (systemd). Feb 03 21:48:52 localhost.localdomain kernel: audit: type=1404 audit(1423000132.274:2): enforcing=1 old_en Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 2048 avtab hash slots, 104131 rules. Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 2048 avtab hash slots, 104131 rules. Feb 03 21:48:52 localhost.localdomain kernel: input: ImExPS/2 Generic Explorer Mouse as /devices/platform/ Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 8 users, 102 roles, 4976 types, 294 bools, 1 sens, Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 83 classes, 104131 rules . . .

You will likely have pages and pages of data to scroll through, which can be tens or hundreds of thousands of lines long if systemd has been on your system for a long while. This demonstrates how much data is available in the journal database.

The format will be familiar to those who are used to standard syslog logging. However, this actually collects data from more sources than traditional syslog implementations are capable of. It includes logs from the early boot process, the kernel, the initrd, and application standard error and out. These are all available in the journal.

You may notice that all of the timestamps being displayed are local time. This is available for every log entry now that we have our local time set correctly on our system. All of the logs are displayed using this new information.

If you want to display the timestamps in UTC, you can use the --utc flag:

  1. journalctl --utc

How to Filter systemd Logs by Time with journalctl

While having access to such a large collection of data is definitely useful, such a large amount of information can be difficult or impossible to inspect and process manually. Because of this, one of the most important features of journalctl is its filtering options.

Show Logs from the Current Boot Session with journalctl

The most basic of these which you might use daily, is the -b flag. This will show you all of the journal entries that have been collected since the most recent reboot.

  1. journalctl -b

This will help you identify and manage information that is pertinent to your current environment.

In cases where you aren’t using this feature and are displaying more than one day of boots, you will see that journalctl has inserted a line that looks like this whenever the system went down:

Output
. . . -- Reboot -- . . .

This can be used to help you logically separate the information into boot sessions.

How to Access Logs from Previous Boots Using journalctl

While you will commonly want to display the information from the current boot, there are certainly times when past boots would be helpful as well. The journal can save information from many previous boots, so journalctl can be made to display information easily.

Some distributions enable saving previous boot information by default, while others disable this feature. To enable persistent boot information, you can either create the directory to store the journal by typing:

  1. sudo mkdir -p /var/log/journal

Or you can edit the journal configuration file:

  1. sudo nano /etc/systemd/journald.conf

Under the [Journal] section, set the Storage= option to “persistent” to enable persistent logging:

/etc/systemd/journald.conf
. . .
[Journal]
Storage=persistent

When saving previous boots is enabled on your server, journalctl provides some commands to help you work with boots as a unit of division. To see the boots that journald knows about, use the --list-boots option with journalctl:

journalctl --list-boots
Output
-2 caf0524a1d394ce0bdbcff75b94444fe Tue 2015-02-03 21:48:52 UTC—Tue 2015-02-03 22:17:00 UTC -1 13883d180dc0420db0abcb5fa26d6198 Tue 2015-02-03 22:17:03 UTC—Tue 2015-02-03 22:19:08 UTC 0 bed718b17a73415fade0e4e7f4bea609 Tue 2015-02-03 22:19:12 UTC—Tue 2015-02-03 23:01:01 UTC

This will display a line for each boot. The first column is the offset for the boot that can be used to easily reference the boot with journalctl. If you need an absolute reference, the boot ID is in the second column. You can tell the time that the boot session refers to with the two time specifications listed towards the end.

To display information from these boots, you can use information from either the first or second column.

For instance, to see the journal from the previous boot, use the -1 relative pointer with the -b flag:

  1. journalctl -b -1

You can also use the boot ID to call back the data from a boot:

  1. journalctl -b caf0524a1d394ce0bdbcff75b94444fe

Filter journalctl Logs by Custom Date and Time Ranges

While seeing log entries by boot is incredibly useful, often you may wish to request windows of time that do not align well with system boots. This may be especially true when dealing with long-running servers with significant uptime.

You can filter by arbitrary time limits using the --since and --until options, which restrict the entries displayed to those after or before the given time, respectively.

The time values can come in a variety of formats. For absolute time values, you should use the following format:

  1. YYYY-MM-DD HH:MM:SS

For instance, we can see all of the entries since January 10th, 2015 at 5:15 PM by typing:

  1. journalctl --since "2015-01-10 17:15:00"

If components of the above format are left off, some defaults will be applied. For instance, if the date is omitted, the current date will be assumed. If the time component is missing, “00:00:00” (midnight) will be substituted. The seconds field can be left off as well to default to “00”:

  1. journalctl --since "2015-01-10" --until "2015-01-11 03:00"

The journal also understands some relative values and named shortcuts. For instance, you can use the words “yesterday”, “today”, “tomorrow”, or “now”. You can do relative times by prepending “-” or “+” to a numbered value or using words like “ago” in a sentence construction.

To get the data from yesterday, you could type:

  1. journalctl --since yesterday

If you received reports of a service interruption starting at 9:00 AM and continuing until an hour ago, you could type:

  1. journalctl --since 09:00 --until "1 hour ago"

As you can see, it’s relatively straightforward to define flexible windows of time to filter the entries you wish to see.

How to Filter systemd Journal Logs by Service, PID, or User

Above, we learned some ways that you can filter the journal data using time constraints. In this section we’ll discuss how to filter based on what service or component you are interested in. The systemd journal provides a variety of ways of doing this.

View Logs by Systemd Service Unit

Perhaps the most useful way of filtering is by the unit you are interested in. We can use the -u option to filter in this way.

For instance, to see all of the logs from an Nginx unit on our system, we can type:

  1. journalctl -u nginx.service

Typically, you would probably want to filter by time as well in order to display the lines you are interested in. For instance, to check on how the service is running today, you can type:

  1. journalctl -u nginx.service --since today

This type of focus becomes extremely helpful when you take advantage of the journal’s ability to interleave records from various units. For instance, if your Nginx process is connected to a PHP-FPM unit to process dynamic content, you can merge the entries from both in chronological order by specifying both units:

  1. journalctl -u nginx.service -u php-fpm.service --since today

This can make it much easier to spot the interactions between different programs and debug systems instead of individual processes.

Filter systemd Logs by PID, UID, or GID

Some services spawn a variety of child processes to do work. If you have scouted out the exact PID of the process you are interested in, you can filter by that as well.

To do this we can filter by specifying the _PID field. For instance if the PID we’re interested in is 8088, we could type:

  1. journalctl _PID=8088

At other times, you may wish to show all of the entries logged from a specific user or group. This can be done with the _UID or _GID filters. For instance, if your web server runs under the www-data user, you can find the user ID by typing:

  1. id -u www-data
Output
33

Afterwards, you can use the ID that was returned to filter the journal results:

  1. journalctl _UID=33 --since today

The systemd journal has many fields that can be used for filtering. Some of those are passed from the process being logged and some are applied by journald using information it gathers from the system at the time of the log.

The leading underscore indicates that the _PID field is of the latter type. The journal automatically records and indexes the PID of the process that is logging for later filtering. You can find out about all of the available journal fields by typing:

  1. man systemd.journal-fields

We will be discussing some of these in this guide. For now though, we will go over one more useful option having to do with filtering by these fields. The -F option can be used to show all of the available values for a given journal field.

For instance, to see which group IDs the systemd journal has entries for, you can type:

  1. journalctl -F _GID
Output
32 99 102 133 81 84 100 0 124 87

This will show you all of the values that the journal has stored for the group ID field. This can help you construct your filters.

View Logs by Executable Path

We can also filter by providing a path location.

If the path leads to an executable, journalctl will display all of the entries that involve the executable in question. For instance, to find those entries that involve the bash executable, you can type:

  1. journalctl /usr/bin/bash

Usually, if a unit is available for the executable, that method is cleaner and provides better info (entries from associated child processes, etc). Sometimes, however, this is not possible.

How to View Kernel Logs Using journalctl -k

Kernel messages, those usually found in dmesg output, can be retrieved from the journal as well.

To display only these messages, we can add the -k or --dmesg flags to our command:

  1. journalctl -k

By default, this will display the kernel messages from the current boot. You can specify an alternative boot using the normal boot selection flags discussed previously. For instance, to get the messages from five boots ago, you could type:

  1. journalctl -k -b -5

Filter Logs by Severity Level with journalctl -p

One filter that system administrators often are interested in is the message priority. While it is often useful to log information at a very verbose level, when actually digesting the available information, low priority logs can be distracting and confusing.

You can use journalctl to display only messages of a specified priority or above by using the -p option. This allows you to filter out lower priority messages.

For instance, to show only entries logged at the error level or above, you can type:

  1. journalctl -p err -b

This will show you all messages marked as error, critical, alert, or emergency. The journal implements the standard syslog message levels. You can use either the priority name or its corresponding numeric value. In order of highest to lowest priority, these are:

  • 0: emerg
  • 1: alert
  • 2: crit
  • 3: err
  • 4: warning
  • 5: notice
  • 6: info
  • 7: debug

The above numbers or names can be used interchangeably with the -p option. Selecting a priority will display messages marked at the specified level and those above it.

Customize journalctl Log Output Display

Above, we demonstrated entry selection through filtering. There are other ways we can modify the output though. We can adjust the journalctl display to fit various needs.

How to Control Output Length and Formatting in journalctl

We can adjust how journalctl displays data by telling it to shrink or expand the output.

By default, journalctl will show the entire entry in the pager, allowing the entries to trail off to the right of the screen. This info can be accessed by pressing the right arrow key.

If you’d rather have the output truncated, inserting an ellipsis where information has been removed, you can use the --no-full option:

  1. journalctl --no-full
Output
. . . Feb 04 20:54:13 journalme sshd[937]: Failed password for root from 83.234.207.60...h2 Feb 04 20:54:13 journalme sshd[937]: Connection closed by 83.234.207.60 [preauth] Feb 04 20:54:13 journalme sshd[937]: PAM 2 more authentication failures; logname...ot

You can also go in the opposite direction with this and tell journalctl to display all of its information, regardless of whether it includes unprintable characters. We can do this with the -a flag:

  1. journalctl -a

How to Disable the Pager in journalctl Output

By default, journalctl displays output in a pager for easier consumption. If you are planning on processing the data with text manipulation tools, however, you probably want to be able to output to standard output.

You can do this with the --no-pager option:

  1. journalctl --no-pager

This can be piped immediately into a processing utility or redirected into a file on disk, depending on your needs.

Different Output Formats in journalctl

If you are processing journal entries, as mentioned above, you most likely will have an easier time parsing the data if it is in a more consumable format. Luckily, the journal can be displayed in a variety of formats as needed. You can do this using the -o option with a format specifier.

For instance, you can output the journal entries in JSON by typing:

  1. journalctl -b -u nginx -o json
Output
{ "__CURSOR" : "s=13a21661cf4948289c63075db6c25c00;i=116f1;b=81b58db8fd9046ab9f847ddb82a2fa2d;m=19f0daa;t=50e33c33587ae;x=e307daadb4858635", "__REALTIME_TIMESTAMP" : "1422990364739502", "__MONOTONIC_TIMESTAMP" : "27200938", "_BOOT_ID" : "81b58db8fd9046ab9f847ddb82a2fa2d", "PRIORITY" : "6", "_UID" : "0", "_GID" : "0", "_CAP_EFFECTIVE" : "3fffffffff", "_MACHINE_ID" : "752737531a9d1a9c1e3cb52a4ab967ee", "_HOSTNAME" : "desktop", "SYSLOG_FACILITY" : "3", "CODE_FILE" : "src/core/unit.c", "CODE_LINE" : "1402", "CODE_FUNCTION" : "unit_status_log_starting_stopping_reloading", "SYSLOG_IDENTIFIER" : "systemd", "MESSAGE_ID" : "7d4958e842da4a758f6c1cdc7b36dcc5", "_TRANSPORT" : "journal", "_PID" : "1", "_COMM" : "systemd", "_EXE" : "/usr/lib/systemd/systemd", "_CMDLINE" : "/usr/lib/systemd/systemd", "_SYSTEMD_CGROUP" : "/", "UNIT" : "nginx.service", "MESSAGE" : "Starting A high performance web server and a reverse proxy server...", "_SOURCE_REALTIME_TIMESTAMP" : "1422990364737973" } . . .

This is useful for parsing with utilities. You could use the json-pretty format to get a better handle on the data structure before passing it off to the JSON consumer:

  1. journalctl -b -u nginx -o json-pretty
Output
{ "__CURSOR" : "s=13a21661cf4948289c63075db6c25c00;i=116f1;b=81b58db8fd9046ab9f847ddb82a2fa2d;m=19f0daa;t=50e33c33587ae;x=e307daadb4858635", "__REALTIME_TIMESTAMP" : "1422990364739502", "__MONOTONIC_TIMESTAMP" : "27200938", "_BOOT_ID" : "81b58db8fd9046ab9f847ddb82a2fa2d", "PRIORITY" : "6", "_UID" : "0", "_GID" : "0", "_CAP_EFFECTIVE" : "3fffffffff", "_MACHINE_ID" : "752737531a9d1a9c1e3cb52a4ab967ee", "_HOSTNAME" : "desktop", "SYSLOG_FACILITY" : "3", "CODE_FILE" : "src/core/unit.c", "CODE_LINE" : "1402", "CODE_FUNCTION" : "unit_status_log_starting_stopping_reloading", "SYSLOG_IDENTIFIER" : "systemd", "MESSAGE_ID" : "7d4958e842da4a758f6c1cdc7b36dcc5", "_TRANSPORT" : "journal", "_PID" : "1", "_COMM" : "systemd", "_EXE" : "/usr/lib/systemd/systemd", "_CMDLINE" : "/usr/lib/systemd/systemd", "_SYSTEMD_CGROUP" : "/", "UNIT" : "nginx.service", "MESSAGE" : "Starting A high performance web server and a reverse proxy server...", "_SOURCE_REALTIME_TIMESTAMP" : "1422990364737973" } . . .

The following formats can be used for display:

  • cat: Displays only the message field itself.
  • export: A binary format suitable for transferring or backing up.
  • json: Standard JSON with one entry per line.
  • json-pretty: JSON formatted for better human-readability
  • json-sse: JSON formatted output wrapped to make add server-sent event compatible
  • short: The default syslog style output
  • short-iso: The default format augmented to show ISO 8601 wallclock timestamps.
  • short-monotonic: The default format with monotonic timestamps.
  • short-precise: The default format with microsecond precision
  • verbose: Shows every journal field available for the entry, including those usually hidden internally.

These options allow you to display the journal entries in whatever format best suits your current needs.

Monitor Live systemd Logs with journalctl

The journalctl command imitates how many administrators use tail for monitoring active or recent activity. This functionality is built into journalctl, allowing you to access these features without having to pipe to another tool.

DShow Recent Log Entries with journalctl -n

To display a set amount of records, you can use the -n option, which works exactly as tail -n.

By default, it will display the most recent 10 entries:

  1. journalctl -n

You can specify the number of entries you’d like to see with a number after the -n:

  1. journalctl -n 20

Follow Real-Time Logs with journalctl -f

To actively follow the logs as they are being written, you can use the -f flag. Again, this works as you might expect if you have experience using tail -f:

  1. journalctl -f

To exit this command, type CTRL+C.

How to Manage and Clean Up systemd Journal Logs

You may be wondering about the cost of storing all of the data we’ve seen so far. Furthermore, you may be interesting in cleaning up some older logs and freeing up space.

Check Disk Usage of systemd Logs with journalctl --disk-usage

You can find out the amount of space that the journal is currently occupying on disk by using the --disk-usage flag:

  1. journalctl --disk-usage
Output
Archived and active journals take up 8.0M in the file system.

Delete Old Logs with journalctl --vacuum-size and --vacuum-time

If you wish to shrink your journal, you can do that in two different ways (available with systemd version 218 and later).

If you use the --vacuum-size option, you can shrink your journal by indicating a size. This will remove old entries until the total journal space taken up on disk is at the requested size:

  1. sudo journalctl --vacuum-size=1G

Another way that you can shrink the journal is providing a cutoff time with the --vacuum-time option. Any entries beyond that time are deleted. This allows you to keep the entries that have been created after a specific time.

For instance, to keep entries from the last year, you can type:

  1. sudo journalctl --vacuum-time=1years

Configure Disk Space Limits for Journald Logs

You can configure your server to place limits on how much space the journal can take up. This can be done by editing the /etc/systemd/journald.conf file.

The following items can be used to limit the journal growth:

  • SystemMaxUse=: Specifies the maximum disk space that can be used by the journal in persistent storage.
  • SystemKeepFree=: Specifies the amount of space that the journal should leave free when adding journal entries to persistent storage.
  • SystemMaxFileSize=: Controls how large individual journal files can grow to in persistent storage before being rotated.
  • RuntimeMaxUse=: Specifies the maximum disk space that can be used in volatile storage (within the /run filesystem).
  • RuntimeKeepFree=: Specifies the amount of space to be set aside for other uses when writing data to volatile storage (within the /run filesystem).
  • RuntimeMaxFileSize=: Specifies the amount of space that an individual journal file can take up in volatile storage (within the /run filesystem) before being rotated.

By setting these values, you can control how journald consumes and preserves space on your server. Keep in mind that SystemMaxFileSize and RuntimeMaxFileSize will target archived files to reach stated limits. This is important to remember when interpreting file counts after a vacuuming operation.

Troubleshooting Common journalctl and systemd Journal Issues

1. Why Is journalctl Not Showing Logs?

In some cases, you might run the journalctl command expecting to see log output, only to be met with a blank screen or no meaningful results. This situation can be confusing, especially if you’re troubleshooting an issue or looking for recent system activity. Fortunately, there are several common explanations that help demystify why journalctl isn’t showing logs.

The Journal Database Is Empty or Missing

One of the most straightforward reasons for seeing no output is that the journal is empty. This can happen on newly installed systems, minimal container environments, or servers where system logging hasn’t yet generated any entries. It’s also possible that your system is configured to only store logs in memory (volatile storage), which means all logs are erased on reboot. To check if persistent logging is enabled, you can look for the presence of the journal directory:

ls /var/log/journal

If this directory doesn’t exist, or if it’s empty, it means that your logs are not being saved between boots. You can resolve this by creating the directory and restarting the journald service:

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

Once persistent logging is enabled, future logs will be written to disk and retained across reboots.

The Logging Service May Not Be Running

Another possibility is that the logging service itself has encountered an error or failed to start. The systemd-journald service is responsible for collecting and managing log data. If it’s not running, the journal will naturally be empty. You can check its status with:

systemctl status systemd-journald

If the service is inactive or has failed, restarting it should restore log collection functionality.

Filters May Be Too Narrow

Sometimes, the issue isn’t with the logs themselves, but with how you’re trying to access them. Using narrow filters, such as a non-existent unit name or overly specific time range, can return no results even when relevant data exists. It’s often helpful to run journalctl without any flags to confirm that logs are being collected, and then progressively apply filters as needed.

Logs May Have Been Rotated or Deleted

Finally, keep in mind that journal logs are subject to size and time-based retention policies. If old logs have been vacuumed by systemd-journald, they will no longer be accessible. You can inspect how much space the journal is currently using with:

journalctl --disk-usage

If you’ve configured your system to limit journal size aggressively, or if you’ve recently run a vacuum command manually, logs may have been purged from the database.

2. Permission Denied When Using journalctl

If you attempt to run journalctl as a regular user and receive a “permission denied” message, you’re not alone. By default, access to system logs is restricted to the root user and members of the systemd-journal group. This restriction is designed to protect potentially sensitive log data, which can contain information about user activity, system processes, and service failures.

Running journalctl with Elevated Privileges

The simplest and most common solution is to run the command with sudo. This elevates your privileges for the duration of the command and allows you to view all system logs:

sudo journalctl

If you’re scripting or frequently inspecting logs, typing sudo every time can become tedious. In such cases, it may be more practical to permanently grant your user access to the journal.

Granting Your User Access via Group Membership

To avoid needing sudo, you can add your user to the systemd-journal group. This group is specially designed to allow non-root users to read journal logs. You can add your user to the group with the following command:

sudo usermod -aG systemd-journal yourusername

Be sure to replace yourusername with your actual login name. After adding the user to the group, you must log out and log back in for the change to take effect. Once that’s done, you should be able to run journalctl without needing elevated privileges.

Verifying Journal Permissions

If group membership doesn’t resolve the issue, there may be a problem with file or directory permissions. The /var/log/journal directory should be owned by root and grouped under systemd-journal. Group read permissions must be set correctly, or access will still be denied even if you’re in the correct group. You can fix this with:

sudo chown root:systemd-journal /var/log/journal
sudo chmod 2755 /var/log/journal

With these permissions and the proper group membership in place, non-root users can access logs securely.

3. Logs Not Persisting After Reboot

If you notice that logs disappear every time your server reboots, your system is likely configured to store logs in volatile memory only, which is lost when the machine powers off. This is a common default in many Linux distributions and container environments, especially those optimized for low disk usage.

Enabling Persistent Logging

To retain logs across reboots, you need to configure journald to use persistent storage. This requires creating the appropriate directory where the journal can write logs to disk. The path /var/log/journal is used for this purpose. If it doesn’t exist, create it and restart the logging daemon:

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

After this is done, all future logs will be written to disk and survive system reboots.

Verifying journald Configuration

If the directory exists but logs still don’t persist, it’s worth inspecting the journald configuration file:

sudo nano /etc/systemd/journald.conf

In this file, look for the Storage= directive under the [Journal] section. If it is set to volatile, change it to persistent:

[Journal]
Storage=persistent

Save the file and restart the service to apply the changes. This ensures the system will write logs to disk instead of RAM from now on.

4. Debugging a Failed systemd Service

When a systemd-managed service fails to start or crashes unexpectedly, journalctl becomes an essential tool for identifying the root cause. Instead of searching through multiple log files, the journal collects all messages related to a service in one place, complete with metadata, timestamps, and priority levels.

Reviewing the Service Status

The first step when troubleshooting is to examine the service status. The systemctl status command provides a snapshot of the service’s current state, including the most recent log entries. For example:

systemctl status nginx.service

This output often reveals immediate issues such as misconfigured paths, permission problems, or exit codes. The exit code and signal information, if present, can be especially helpful for determining whether the service failed on its own or was killed by the system.

Viewing the Full Log History

To see all logs related to the failed service, use journalctl with the -u flag:

journalctl -u nginx.service

This provides a chronological view of messages generated by the service. If you’re trying to diagnose a failure that happened during the last system boot, it’s helpful to limit the output to just that session:

journalctl -u nginx.service -b

Investigating Failure Context

You can often get to the heart of the issue by reading the log entries from a few minutes before and after the failure. Use time-based filters to narrow your focus:

journalctl -u nginx.service --since "10 minutes ago"

This can help identify whether the problem was isolated or part of a larger system issue.

For deeper analysis, you can enable verbose output or view extended error messages using:

journalctl -xe

This command highlights priority messages and recent failures, which can be useful when a service doesn’t leave obvious clues in the standard output.

5. Monitoring SSH Login Attempts

SSH is a primary access method for most Linux servers, which also makes it a common vector for brute-force attacks, unauthorized access attempts, or general auditing. Fortunately, journalctl allows you to monitor all SSH-related activity with ease.

Viewing SSH Logs

Systemd tracks SSH activity under the sshd or ssh unit, depending on your distribution. To see all entries related to SSH:

journalctl -u ssh.service

or, on some systems:

journalctl -u sshd.service

These logs include login attempts, authentication failures, session closures, and key negotiation messages. It’s an excellent first step when verifying who accessed the server and when.

Following SSH Activity in Real Time

For real-time monitoring, you can use journalctl in follow mode. This is especially useful if you suspect an intrusion or want to keep an eye on active login attempts:

journalctl -f -u ssh.service

Each new login event will be printed live as it happens, making it easier to spot failed logins or rapid connection attempts that may indicate malicious behavior.

Filtering by Login Events

If you’re looking for specific login messages, such as failed passwords or accepted connections, you can filter the journal output using keyword matches:

journalctl -u ssh.service | grep "Failed password"
journalctl -u ssh.service | grep "Accepted password"

These messages indicate whether a login was successful and which user attempted it. You can combine these with time filters to narrow the search to a specific window:

journalctl -u ssh.service --since "1 hour ago"

This can be extremely helpful during security audits or forensic investigations.

Frequently Asked Questions (FAQs)

1. Why does journalctl require root access?

By default, journalctl requires root access because it can expose sensitive information collected from system services, kernel messages, user sessions, and background daemons. These logs may include usernames, environment variables, error traces, authentication attempts, and other details that could pose a security risk if accessed by unauthorized users.

To safeguard this data, systemd restricts access to the system journal. However, you don’t always need to use sudo. Non-root users can read logs if they are part of the systemd-journal group. You can add your user to this group with:

sudo usermod -aG systemd-journal yourusername

After logging out and back in, you should be able to access logs without elevated privileges, as long as file permissions on the journal directories are properly configured.

2. How do I make logs persistent across reboots?

To preserve logs after a reboot, you need to configure systemd-journald to use persistent storage rather than volatile memory. By default, some distributions store logs in /run/log/journal, a temporary directory cleared at shutdown. To enable persistent logging:

  1. Create the persistent journal directory:

    sudo mkdir -p /var/log/journal
    
  2. Set permissions if needed:

    sudo systemd-tmpfiles --create --prefix /var/log/journal
    
  3. Restart the journal daemon:

    sudo systemctl restart systemd-journald
    
  4. Optional: Verify or edit configuration:

    Open /etc/systemd/journald.conf and ensure the following line is set:

    Storage=persistent
    

This configuration ensures your system retains log data across reboots, making it easier to audit and debug historical issues.

3. Can I clear journalctl logs?

Yes, journalctl allows you to clear logs using the --vacuum-* options provided by systemd-journald. These commands help reduce disk usage by deleting old or excess log data.

Here are common methods to clear or shrink journal logs:

  • Remove logs older than a specific time:

    sudo journalctl --vacuum-time=2weeks
    
  • Limit total disk usage for all logs:

    sudo journalctl --vacuum-size=500M
    
  • Restrict the number of journal files kept:

    sudo journalctl --vacuum-files=10
    

These commands do not erase current or recent logs unless they exceed the defined threshold. To fully remove all logs, you can manually delete the journal files from /var/log/journal, but this is rarely necessary and not generally recommended for production systems.

4. How do I access systemd logs?

You can access systemd logs using the journalctl command, which interfaces directly with the systemd journal. All logs related to services managed by systemd, such as boot messages, unit failures, and runtime errors, are stored in the journal.

For general access:

journalctl

To see logs for a specific systemd service, such as nginx, use:

journalctl -u nginx.service

You can also filter by boot session, priority level, time range, or combine multiple services to gain deeper insight. Unlike traditional log files, journalctl provides a unified, indexed view of log messages from multiple sources.

5. Which command is used to view systemd logs?

The primary command used to view systemd logs is:

journalctl

This tool is included with systemd and provides access to all logs collected by the systemd-journald service, including kernel messages, early boot logs, system services, and user sessions.

You can tailor the command with various options:

  • View logs for a specific service:

    journalctl -u ssh.service
    
  • Filter logs by priority:

    journalctl -p err
    
  • Display logs in real time:

    journalctl -f
    

This makes journalctl the most versatile and comprehensive utility for viewing systemd-related logs.

6. How to see kernel logs through journalctl?

Kernel messages, such as those traditionally viewed using dmesg, are also available through the systemd journal. To display only kernel messages using journalctl, use the -k flag:

journalctl -k

This command filters the output to include only messages originating from the kernel. It is especially useful for diagnosing hardware issues, kernel module problems, or boot-time errors. You can also use the -b option to show messages from the current or previous boot:

journalctl -k -b -1

This gives you consistent access to kernel logs, integrated with logs from other services for better contextual understanding.

7. What is the difference between dmesg and journalctl?

While both dmesg and journalctl can show kernel logs, they serve different purposes and operate under different mechanisms.

Feature dmesg journalctl
Scope Kernel ring buffer only Kernel + system + userland logs
Persistence Cleared on reboot or buffer full Persistent (if enabled)
Metadata No structured metadata Rich metadata (unit, PID, UID, etc.)
Filtering Limited Extensive filtering capabilities
Output formats Raw, simple JSON, export, short, verbose, etc.
Permissions Requires sudo for full output Requires root or group membership

In short, dmesg is limited to low-level kernel logs in real time, while journalctl offers a more complete, structured, and persistent logging interface that encompasses the entire system.

Conclusion

As you can see, the systemd journal is incredibly useful for collecting and managing your system and application data. Most of the flexibility comes from the extensive metadata automatically recorded and the centralized nature of the log.

In this guide, we covered basic log viewing, time-based and field-based filtering, monitoring kernel and service logs, output formatting, and real-time log tracking. We also discussed journal maintenance, storage limits, and troubleshooting common issues like missing logs or permission errors.

The journalctl command makes it easy to take advantage of the advanced features of the journal and to do extensive analysis and relational debugging of different application components. By mastering journalctl, you gain a versatile, unified logging interface for debugging, monitoring, and auditing across your entire system.

For more detailed insight into logging and troubleshooting on Linux systems, explore the following related tutorials:

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Justin Ellingwood
Justin Ellingwood
Author
See author profile

Former Senior Technical Writer at DigitalOcean, specializing in DevOps topics across multiple Linux distributions, including Ubuntu 18.04, 20.04, 22.04, as well as Debian 10 and 11.

Manikandan Kurup
Manikandan Kurup
Editor
Senior Technical Content Engineer I
See author profile

With over 6 years of experience in tech publishing, Mani has edited and published more than 75 books covering a wide range of data science topics. Known for his strong attention to detail and technical knowledge, Mani specializes in creating clear, concise, and easy-to-understand content tailored for developers.

Still looking for an answer?

Was this helpful?


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Nice post. Bookmarked!

Another great tutorial. I especially like filtering on error levels and the option to limit log file storage size.

Usefull!

Thank you for this :)

Thank you, this is a great introduction to journald!

Thank you. Its a nice explanation. I have a question: I have set RuntimeMaxUse=32M. With this value, I am expecting 7 archive files and one active journal file. But I am getting 8 archive files each of 4M and one active journal file (4M). So in total it is taking 36M, instead of RuntimeMaxUse=32M. Is it a bug ? or expected behavior ?

Good article, Thank you for the explanation :)

You lied to me:

" This will show you all of the journal entries that have been collected since the most recent reboot.

journalctl -b "

But that shows me messages like this: systemd-journald[217]: Missed 1 kernel messages which I have to see with this: $ journalctl -b --dmesg but then if I do that, then a bunch of other messages are gone, like: CROND[7261]: (root) CMD (run-parts /etc/cron.hourly) and systemd-coredump[6109]: Process 5527 (Web Content) of user…

So the question is, how can I see them all? tried: -a (still doesn’t show me the missed kernel ones, but shows all others - just like -b does, I guess -a is implied) and $ journalctl -efa _TRANSPORT=kernel + _TRANSPORT=syslog -m but this one still doesn’t show me the coredump one, but shows all others

Or what are the matches for -a ? so that I can concat them with + to the ones I mentioned and then I’d have the real -a (aka ALL, what -a is supposed to be doing) In other words what’s the equivalent of -a in MATCHES? apparently _TRANSPORT=syslog is part of that but _TRANSPORT=kernel isn’t

pretty useful!

Very clear and usefull. Thank you!

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.