Parsing JSON logs locally

Introduction

JSON/JSONL logs are, in my opinion, a good way to log from your application to a file. The structured nature makes them easily programatically parsed. This works great with tools like graphana and loki, however I'ved noticed that parsing them locally isn't as straightforward as you might expect.

In this post, I'm going to go over the ways I view and process logs, locally, on my work machine.
I will be using CLI and TUI tools only.

The tools

There are many tools to visualise and navigate json or jsonl data:

And there are tools to filter json:

But to interactively do both, this is where it gets more tricky

Combining the tools

Here are some of the techniques I've come up with to combine the tools to get the best of both worlds.

jq + jless

jq is by far my favourite json filterer/processor. It's fast and well documented and supported.
jless is up until now, my favourite json viewer. I like it's documentation better than fx, and it's written in rust instead of javascript.

Here is a sample command to parse some jsonl logs:

cat application_name.log.jsonl | jq 'select(.level != "DEBUG")' | jless

I used cat to keep the file I'm passing in, nice and separate from the filter command, but it's also possible to pass the file as a 2nd parameter to jq and only have to pipe data once.

ijq + jless

jq can be a bit hard to learn at first, so an interactive approach is welcome. ijq allows us to interactively try filters and see the output change in real time. Once we are happy with the output, we can then send it to jless for further viewing

cat application_name.log.jsonl | ijq | jless

or the upgraded version which will also copy the filter to your clipboard (on macos only). If you want this to work on linux, you need to replace pbcopy with xclip -selection clipboard
This allows you to use the filter in jq later on if needed.

cat application_name.log.jsonl | ijq 2> >(pbcopy) | jless

The copy thing works because ijq outputs the filter to stderr and the json result to stdout.
We are are using process substitution to pass stderr to pbcopy (or xclip) and stdout to jless.