43.6 journalctl Filters: -u, --since, --until, -p, -f
Right, so journalctl is your new best friend and your worst critic, all wrapped into one. It’s the primary tool for reading the structured, indexed journal that systemd creates, and if you’re just running it naked, you’re doing it wrong. You’ll be buried in a firehose of data, from the very first boot message to the kernel’s latest hiccup. The power, and the point, is in the filters. Let’s talk about the ones you’ll use every single day.
The Unit Filter: -u
This is the big one. You don’t care about all the logs, you care about the logs for the specific service you’re debugging. The -u or --unit flag is your precision scalpel.
journalctl -u nginx.service
This shows you everything the nginx unit has ever logged to stdout/stderr. Why is this so crucial? Because systemd neatly collects the output of every service it manages into the journal. This command cuts through the noise of every other service on the machine and shows you only the story of your service: when it started, when it stopped, any errors it spat out, and any custom messages it logged. It’s the first and last command you run when a service misbehaves.
You can also follow a unit’s logs in real-time, which is indispensable for watching a service start up.
journalctl -u my-weird-app.service -f
A quick tip: you don’t strictly need the .service part. journalctl -u nginx works just fine. systemd is smart enough to figure it out.
Time Travel: –since and –until
The journal is indexed by time, so filtering by it is incredibly fast and useful. The syntax is wonderfully flexible, accepting absolute times ("2024-01-01 00:00:00") or relative times ("yesterday", "1 hour ago"), which is frankly the way all CLI tools should work.
Need to see what happened in the last ten minutes across all services after you deployed a new config?
journalctl --since "10 minutes ago"
Trying to figure out what caused that alert at 2:14 AM last night? Combine time with your unit filter.
journalctl -u database.service --since "02:00" --until "02:30"
The designers get a rare, unreserved gold star here. The relative time parsing is robust and intuitive. Use it. Love it.
Priority Filter: -p
Not all log messages are created equal. A “debug” message is noise 99.9% of the time. An “emerg” message means you probably have a page waiting for you. The -p or --priority filter lets you see only messages of a specified priority level and higher. This is a lifesaver.
The levels are numeric (0-7) but you can use the names. To see only messages at the ERROR level and above (that’s err, crit, alert, emerg):
journalctl -p err -b
Why is it “and above”? Because if you’re looking for errors, you almost certainly also want to see the criticals and emergencies. It’s a logical hierarchy. The common pitfall is forgetting this inclusive nature and thinking -p err shows only err. Nope. It shows err and everything more severe.
Want to see only warnings and nothing else? You can’t do that directly with -p. You’d have to use a tool like grep afterwards, which is a bit of a design oversight, but we work with what we have.
The Follow Flag: -f
This one’s simple but so vital it deserves its own mention. -f or --follow is the tail -f of the journal. It shows you the last few lines and then follows the journal, outputting new messages as they come in. It’s the ultimate tool for watching a service start live or monitoring a deployment.
Always, always combine it with a unit filter unless you enjoy the sensation of your console blinking into insanity.
journalctl -u api-service -f
Putting It All Together: The Art of the Query
The real magic happens when you combine these. The journal is a database, and you’re constructing a query. You can build incredibly specific commands to answer precise questions.
“What were the error-level messages from the redis service between 9 AM and 10 AM today?”
journalctl -u redis -p err --since "09:00" --until "10:00"
“Show me the logs for the docker service from the previous boot, and follow any new ones.”
journalctl -u docker -b -1 -f
The key insight is that the journal is designed for this. These filters operate on indexed fields, so they’re lightning fast. Using grep on the full journal output is a clumsy, slow last resort. Use the built-in filters first. They’re your brilliant, witty, and direct way to cut to the chase.