I've found another use case for `jq` when parsing service logs stored with `journald`. This time, I want to extract all non-INFO level logs from the service called slinky. In the previous example, I used `awk` to print only the part of a line that is valid JSON. However, `sed` might be better suited for this task. The following rule removes (replaces with an empty string) the beginning of the line up to the colon followed by a space ": ", which separates the timestamp from the log entry (JSON):
's/^.\+\]:\ //'
Examples
There are two examples of the command pipelines below.
The first one checks the logs from the last 2 hours:
journalctl --since "2 hours ago" -u slinky.service\ | sed -e 's/^.\+\]:\ //'\ | jq 'select(.level != "info") '
The second one continuously prints new entries:
journalctl -f -u slinky.service\ | stdbuf -oL sed -e 's/^.\+\]:\ //'\ | jq 'select(.level != "info") '
The `journalctl` command is nearly identical in both examples (`--since` vs. `-f`). The `jq` select statement and the `sed` string replacement are the same. The main difference is that the latter uses the `stdbuf` command. It allows running the following command with modified buffering. The `-oL` option means that the standard output of the `sed` command is flushed line by line, enabling each entry to be passed immediately to `jq`.