github.com/neilotoole/jsoncolor@v0.6.0/README.md (about) 1 [](https://github.com/neilotoole/jsoncolor/actions?query=workflow%3AGo) 2 [](https://goreportcard.com/report/neilotoole/jsoncolor) 3 [](https://github.com/neilotoole/jsoncolor/releases/tag/v0.6.0) 4 [](https://pkg.go.dev/github.com/neilotoole/jsoncolor) 5 [](./LICENSE) 6 7 # jsoncolor 8 9 Package `neilotoole/jsoncolor` is a drop-in replacement for `encoding/json` 10 that outputs colorized JSON. 11 12 Why? Well, `jq` colorizes its output by default, and color output is desirable for 13 many Go CLIs. This package performs colorization (and indentation) inline in the encoder, 14 and is significantly faster than stdlib at indentation. 15 16 From the example [`jc`](cmd/jc) app: 17 18  19 20 ## Usage 21 22 Get the package per the normal mechanism: 23 24 ```shell 25 go get -u github.com/neilotoole/jsoncolor 26 ``` 27 28 Then: 29 30 ```go 31 package main 32 33 import ( 34 "fmt" 35 "github.com/mattn/go-colorable" 36 json "github.com/neilotoole/jsoncolor" 37 "os" 38 ) 39 40 func main() { 41 var enc *json.Encoder 42 43 // Note: this check will fail if running inside Goland (and 44 // other IDEs?) as IsColorTerminal will return false. 45 if json.IsColorTerminal(os.Stdout) { 46 // Safe to use color 47 out := colorable.NewColorable(os.Stdout) // needed for Windows 48 enc = json.NewEncoder(out) 49 50 // DefaultColors are similar to jq 51 clrs := json.DefaultColors() 52 53 // Change some values, just for fun 54 clrs.Bool = json.Color("\x1b[36m") // Change the bool color 55 clrs.String = json.Color{} // Disable the string color 56 57 enc.SetColors(clrs) 58 } else { 59 // Can't use color; but the encoder will still work 60 enc = json.NewEncoder(os.Stdout) 61 } 62 63 m := map[string]interface{}{ 64 "a": 1, 65 "b": true, 66 "c": "hello", 67 } 68 69 if err := enc.Encode(m); err != nil { 70 fmt.Fprintln(os.Stderr, err) 71 os.Exit(1) 72 } 73 } 74 ``` 75 76 77 ### Configuration 78 79 To enable colorization, invoke `enc.SetColors`. 80 81 The `jsoncolor.Colors` struct holds color config. The zero value 82 and `nil` are both safe for use (resulting in no colorization). 83 84 The `DefaultColors` func returns a `Colors` struct that produces results 85 similar to `jq`: 86 87 ```go 88 // DefaultColors returns the default Colors configuration. 89 // These colors largely follow jq's default colorization, 90 // with some deviation. 91 func DefaultColors() *Colors { 92 return &Colors{ 93 Null: Color("\x1b[2m"), 94 Bool: Color("\x1b[1m"), 95 Number: Color("\x1b[36m"), 96 String: Color("\x1b[32m"), 97 Key: Color("\x1b[34;1m"), 98 Bytes: Color("\x1b[2m"), 99 Time: Color("\x1b[32;2m"), 100 Punc: Color{}, // No colorization 101 } 102 } 103 ``` 104 105 As seen above, use the `Color` zero value (`Color{}`) to 106 disable colorization for that JSON element. 107 108 109 ### Helper for `fatih/color` 110 111 It can be inconvenient to use terminal codes, e.g. `json.Color("\x1b[36m")`. 112 A helper package provides an adapter for [`fatih/color`](https://github.com/fatih/color). 113 114 ```go 115 // import "github.com/neilotoole/jsoncolor/helper/fatihcolor" 116 // import "github.com/fatih/color" 117 118 out := colorable.NewColorable(os.Stdout) // needed for Windows 119 enc = json.NewEncoder(out) 120 121 fclrs := fatihcolor.DefaultColors() 122 // Change some values, just for fun 123 fclrs.Number = color.New(color.FgBlue) 124 fclrs.String = color.New(color.FgCyan) 125 126 clrs := fatihcolor.ToCoreColors(fclrs) 127 enc.SetColors(clrs) 128 ``` 129 130 ### Drop-in for `encoding/json` 131 132 This package is a full drop-in for stdlib `encoding/json` 133 (thanks to the `segmentio/encoding/json` pkg being a full drop-in). 134 135 To drop-in, just use an import alias: 136 137 ```go 138 import json "github.com/neilotoole/jsoncolor" 139 ``` 140 141 ### History 142 143 This package is an extract of [`sq`](https://github.com/neilotoole/sq)'s JSON encoding 144 package, which itself is a fork of the [`segment.io/encoding`](https://github.com/segmentio/encoding) JSON 145 encoding package (aka `segmentj`). 146 147 Note that the original `jsoncolor` codebase was forked from Segment's codebase at `v0.1.14`, so 148 the codebases are quite of out sync by now. 149 150 ## Example app: `jc` 151 152 See [`cmd/jc`](cmd/jc) for a trivial CLI implementation that can accept JSON input, 153 and output that JSON in color. 154 155 ```shell 156 # From project root 157 $ go install ./cmd/jc 158 $ cat ./testdata/sakila_actor.json | jc 159 ``` 160 161 ## Benchmarks 162 163 Note that this package contains `golang_bench_test.go`, which is inherited from `segmentj`. 164 But we're mainly interested in `benchmark_test.go:BenchmarkEncode`. The results below benchmark 165 the following: 166 167 - Stdlib `encoding/json` (`go1.17.1`). 168 - [`segmentj`](https://github.com/segmentio/encoding): `v0.1.14`, which was when `jsoncolor` was forked. The newer `segmentj` code performs even better. 169 - `neilotoole/jsoncolor`: (this package) `v0.6.0`. 170 - [`nwidger/jsoncolor`](https://github.com/nwidger/jsoncolor): `v0.3.0`, latest at time of benchmarks. 171 172 Note that two other Go JSON colorization packages ([`hokaccha/go-prettyjson`](https://github.com/hokaccha/go-prettyjson) and 173 [`TylerBrock/colorjson`](https://github.com/TylerBrock/colorjson)) are excluded from 174 these benchmarks because they do not provide a stdlib-compatible `Encoder` impl. 175 176 177 ``` 178 $ go test -bench=BenchmarkEncode -benchtime="5s" 179 goarch: amd64 180 pkg: github.com/neilotoole/jsoncolor 181 cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz 182 BenchmarkEncode/stdlib_NoIndent-16 181 33047390 ns/op 8870685 B/op 120022 allocs/op 183 BenchmarkEncode/stdlib_Indent-16 124 48093178 ns/op 10470366 B/op 120033 allocs/op 184 BenchmarkEncode/segmentj_NoIndent-16 415 14658699 ns/op 3788911 B/op 10020 allocs/op 185 BenchmarkEncode/segmentj_Indent-16 195 30628798 ns/op 5404492 B/op 10025 allocs/op 186 BenchmarkEncode/neilotoole_NoIndent_NoColor-16 362 16522399 ns/op 3789034 B/op 10020 allocs/op 187 BenchmarkEncode/neilotoole_Indent_NoColor-16 303 20146856 ns/op 5460753 B/op 10021 allocs/op 188 BenchmarkEncode/neilotoole_NoIndent_Color-16 295 19989420 ns/op 10326019 B/op 10029 allocs/op 189 BenchmarkEncode/neilotoole_Indent_Color-16 246 24714163 ns/op 11996890 B/op 10030 allocs/op 190 BenchmarkEncode/nwidger_NoIndent_NoColor-16 10 541107983 ns/op 92934231 B/op 4490210 allocs/op 191 BenchmarkEncode/nwidger_Indent_NoColor-16 7 798088086 ns/op 117258321 B/op 6290213 allocs/op 192 BenchmarkEncode/nwidger_indent_NoIndent_Colo-16 10 542002051 ns/op 92935639 B/op 4490224 allocs/op 193 BenchmarkEncode/nwidger_indent_Indent_Color-16 7 799928353 ns/op 117259195 B/op 6290220 allocs/op 194 ``` 195 196 As always, take benchmarks with a large grain of salt, as they're based on a (small) synthetic benchmark. 197 More benchmarks would give a better picture (and note as well that the benchmarked `segmentj` is an older version, `v0.1.14`). 198 199 All that having been said, what can we surmise from these particular results? 200 201 - `segmentj` performs better than `stdlib` at all encoding tasks. 202 - `jsoncolor` performs better than `segmentj` for indentation (which makes sense, as indentation is performed inline). 203 - `jsoncolor` performs better than `stdlib` at all encoding tasks. 204 205 Again, trust these benchmarks at your peril. Create your own benchmarks for your own workload. 206 207 ## Notes 208 209 - The `.golangci.yml` linter settings have been fiddled with to hush linting issues inherited from 210 the `segmentio` codebase at the time of forking. Thus, the linter report may not be of great use. 211 In an ideal world, the `jsoncolor` functionality would be [ported](https://github.com/neilotoole/jsoncolor/issues/15) to a more recent (and better-linted) 212 version of the `segementio` codebase. 213 - The `segmentio` encoder (at least as of `v0.1.14`) encodes `time.Duration` as string, while `stdlib` outputs the `int64`. 214 This package follows `stdlib`. 215 - The `Colors.Punc` field controls all punctuation colorization, i.e. `[]{},:"`. It is probably worthwhile to [separate](https://github.com/neilotoole/jsoncolor/issues/16) 216 these out into individually-configurable elements. 217 218 ## Acknowledgments 219 220 - [`jq`](https://stedolan.github.io/jq/): sine qua non. 221 - [`segmentio/encoding`](https://github.com/segmentio/encoding): `jsoncolor` is layered into Segment's JSON encoder. They did the hard work. Much gratitude to that team. 222 - [`sq`](https://github.com/neilotoole/sq): `jsoncolor` is effectively an extract of the code created specifically for `sq`. 223 - [`mattn/go-colorable`](https://github.com/mattn/go-colorable): no project is complete without `mattn` having played a role. 224 - [`fatih/color`](https://github.com/fatih/color): the color library. 225 226 ### Related 227 228 - [`nwidger/jsoncolor`](https://github.com/nwidger/jsoncolor) 229 - [`hokaccha/go-prettyjson`](https://github.com/hokaccha/go-prettyjson) 230 - [`TylerBrock/colorjson`](https://github.com/TylerBrock/colorjson)