English Articles

Work with JSON from Go and command line

Go standard library

In Go creating of the JSON quite simple, just pass any data in json.Marshal, and you get the bytes with JSON. But parsing of JSON is painful, especially when you want only one field that located deep in the source JSON. You have to create all maps and structs for all places where located fields that you need. See full example on Go by Example.

Make it better

Command line

You can beautify output of any command that writes JSON logs to stdout just piping it to jq:

$ go run tmp.go | jq
{
  "level": "info",
  "message": "hello world!"
}
{
  "level": "info",
  "message": "hello again",
  "testInt": 0
}

However, jq fails if the input contains non-JSON lines. I don’t know how to fix it. I’ve found isuue where authors recommend to use --seq key for it, but it doesn’t work for me. In this case, you can use bat – a clone of cat with syntax highlighting, lines numbering, pagination and git support.

go run tmp.go | bat -l jsonnet
───────┬──────────────────────────────────────────────────────
       │ STDIN
───────┼──────────────────────────────────────────────────────
   1   │ broke
   2   │ {"level":"info","message":"hello world!"}
   3   │ broke again
   4   │ {"level":"info","message":"hello again","testInt":0}

Appendix

Code that I used for tests:

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/francoispqt/onelog"
)

func main() {
	fmt.Println("broke")
	logger := onelog.New(os.Stdout, onelog.ALL)
	logger.Info("hello world!")
	fmt.Println("broke again")
	for i := 0; true; i++ {
		time.Sleep(2 * time.Second)
		logger.InfoWith("hello again").Int("testInt", i).Write()
	}
}
created: 2019-03-08 (Fri) updated: 2019-03-08 (Fri) views: 87

Contributors

orsinium