Search This Blog

Monday, March 30, 2026

More jq from journalctl

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.

Monday, March 02, 2026

Download GitHub Actions logs

I've been using GitHub CLI more and more lately. Recently, I had to debug a failing of GitHub Action run. Browsing long logs in the WebUI is a bit clunky, so I started downloading the full logs via the CLI. 

It is straightforward `gh` command if you already know the run number --  and that information can be obtained from the `gh` command with different options. 

I end up with following two-part shell snippet: 

VIEW=$(\
 gh run list \
 | grep $(git branch --show-current) \
 | head -1\
 | awk '{print $(NF-2)}') \
&& \
gh run view ${VIEW} --log > ~/Downloads/${VIEW}.log
 

The first command assign the run number to the VIEW variable. It parses the output of the `gh run list` command by:

  • filtering run for the current git branch (`grep`)
  • taking the most recent one (`head`)
  • extracting the run number (third column from the end via `awk`).

The VIEW variable is then used to fetch the logs for the specific run and save them to the uniquely named file in the Downloads folder.

Assumptions:

  • the workflow run belongs to the current git branch
  • it's the latest run for the branch 
  • The Downloads folder doesn't already contain a file with the same number (it would be overwritten)