18.6 journald: Structured Binary Log Store
Right, let’s talk about journald. You know all those little text files in /var/log that every service and its dog scrambles to write to? Syslog? Yeah, journald is systemd’s answer to that, and it’s a complete architectural overhaul. It throws out the concept of plain text log files and replaces it with a single, structured, binary log store. This freaks out a lot of old-school admins, and I get it. It feels like they’re taking away your tail -f /var/log/syslog security blanket. But trust me, once you get over the initial shock, you’ll see it’s like trading a horse and cart for a sports car. It’s just a different kind of machine.
The core idea is brilliant: instead of having fifty different services all fighting to append lines to a text file, everyone just sends their log messages to journald (via a socket). journald then takes these messages, slaps a ton of metadata on them (like the exact timestamp, the PID, the unit name, the user, the priority, etc.), and writes them in a efficient binary format to its own files, usually in /var/log/journal. This metadata is the secret sauce. It turns your logs from a pile of text you have to grep through into a queryable dataset.
The journalctl Swiss Army Knife
You don’t cat or tail the journal. You use its dedicated tool, journalctl. Forget grep as your first instinct. Your new first instinct is to filter by these metadata fields. Want to see everything from the nginx service?
journalctl -u nginx.service
Want to see only kernel messages from the last boot?
journalctl -k -b
Want to see all errors and worse since yesterday? This is where it starts to feel like magic.
journalctl -p err..alert --since yesterday
The -f flag still works for following new messages, just like tail -f. The key shift is to stop thinking in terms of files and start thinking in terms of a database you query. This is the way.
Why Binary? And Where Are My Files?
The binary format isn’t just there to annoy you. It’s for efficiency and integrity. Writing structured data with metadata to a binary file is faster and takes less space than the equivalent text would (they also do compression). It also allows for more secure tamper detection, though it’s not a full audit trail. The files are in /var/log/journal/ by default, but if that directory doesn’t exist, journald politely—and somewhat uselessly—keeps the logs only in a ring buffer in RAM until reboot. This is a common “wait, where are my logs?!” moment. To make it persistent, you just create the directory and restart journald:
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
The Power of Structured Fields
This is the killer feature. Every log entry has fields like _SYSTEMD_UNIT, _PID, _COMM, _EXE, PRIORITY. You can use these to build incredibly precise queries. Let’s say your webapp.service is misbehaving and you want to see its logs, but only for the specific process that just crashed, and you want to see the environment variables it was running with. You can do that.
# Find the PID of the recent failed process for the unit
journalctl -u webapp.service --since "5 minutes ago" -o json-pretty | grep PID
# Now, get everything for that specific PID, showing the fields
journalctl _PID=1234 -o verbose
# This will show you all the metadata, including the environment (`_ENVIRONMENT`) if it was logged.
The -o verbose flag is your best friend for debugging why something is logged the way it is.
The -b Flag and Your Boot Journey
The journal is aware of system boots. Each boot gets a unique identifier. This is fantastic for debugging things that, you know, only happen at boot. journalctl -b shows you the current boot. journalctl -b -1 shows you the previous boot. journalctl -b -0 shows the current one, -b -1 the one before, and so on. You can also list all boot IDs with journalctl --list-boots. Trying to figure out why your machine rebooted? This is your first stop.
Pitfalls and Rough Edges
It’s not all roses. The biggest gripe is that some applications still insist on managing their own log files, bypassing journald entirely, so you can’t use your fancy journalctl queries on them. You have to go back to tail -f for those, which is a shame.
Another legitimate complaint is that the binary format means you can’t just use rsyslog or logrotate on it. systemd provides its own rotation mechanism, configured in /etc/systemd/journald.conf. You set size limits and time limits there. The main setting is SystemMaxUse=, which defines the maximum disk space the journal can use. It’s smart and will delete oldest logs first to stay under this limit. Set this to something sane for your system.
Also, while journalctl -f is great, the default pager it uses can be clunky. If you prefer less, set the environment variable SYSTEMD_LESS to your preferred options (I use SYSTEMD_LESS=FRXMK) to make it behave more sensibly.
Ultimately, journald is a tool that demands you learn its language. If you try to use it like syslog, you’ll be frustrated. If you lean into its strengths—structured data, powerful filtering, and boot awareness—you’ll wonder how you ever lived without it. It’s a definitive upgrade, even if it sometimes feels like the designers made the query syntax just slightly too arcane on purpose. They probably thought it made them look clever. Don’t worry, you’ll be cleverer for learning it.