github.com/neilotoole/jsoncolor@v0.7.2-0.20231115150201-1637fae69be1/README.md (about) 1 [![Actions Status](https://github.com/neilotoole/jsoncolor/workflows/Go/badge.svg)](https://github.com/neilotoole/jsoncolor/actions?query=workflow%3AGo) 2 [![Go Report Card](https://goreportcard.com/badge/neilotoole/jsoncolor)](https://goreportcard.com/report/neilotoole/jsoncolor) 3 [![release](https://img.shields.io/badge/release-v0.7.0-green.svg)](https://github.com/neilotoole/jsoncolor/releases/tag/v0.7.0) 4 [![Go Reference](https://pkg.go.dev/badge/github.com/neilotoole/jsoncolor.svg)](https://pkg.go.dev/github.com/neilotoole/jsoncolor) 5 [![license](https://img.shields.io/github/license/neilotoole/jsoncolor)](./LICENSE) 6 7 # jsoncolor 8 9 Package `neilotoole/jsoncolor` is a drop-in replacement for stdlib 10 [`encoding/json`](https://pkg.go.dev/encoding/json) that outputs colorized JSON. 11 12 Why? Well, [`jq`](https://jqlang.github.io/jq/) colorizes its output by default, and color output 13 is desirable for many Go CLIs. This package performs colorization (and indentation) inline 14 in the encoder, and is significantly faster than stdlib at indentation. 15 16 From the example [`jc`](./cmd/jc/main.go) app: 17 18 ![jsoncolor-output](./splash.png) 19 20 ## Usage 21 22 Get the package per the normal mechanism (requires Go 1.16+): 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 ### Configuration 77 78 To enable colorization, invoke [`enc.SetColors`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#Encoder.SetColors). 79 80 The [`Colors`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#Colors) struct 81 holds color config. The zero value and `nil` are both safe for use (resulting in no colorization). 82 83 The [`DefaultColors`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#DefaultColors) func 84 returns a `Colors` struct that produces results similar to `jq`: 85 86 ```go 87 // DefaultColors returns the default Colors configuration. 88 // These colors largely follow jq's default colorization, 89 // with some deviation. 90 func DefaultColors() *Colors { 91 return &Colors{ 92 Null: Color("\x1b[2m"), 93 Bool: Color("\x1b[1m"), 94 Number: Color("\x1b[36m"), 95 String: Color("\x1b[32m"), 96 Key: Color("\x1b[34;1m"), 97 Bytes: Color("\x1b[2m"), 98 Time: Color("\x1b[32;2m"), 99 Punc: Color{}, // No colorization 100 } 101 } 102 ``` 103 104 As seen above, use the `Color` zero value (`Color{}`) to 105 disable colorization for that JSON element. 106 107 ### Helper for `fatih/color` 108 109 It can be inconvenient to use terminal codes, e.g. `json.Color("\x1b[36m")`. 110 A helper package provides an adapter for [`fatih/color`](https://github.com/fatih/color). 111 112 ```go 113 // import "github.com/neilotoole/jsoncolor/helper/fatihcolor" 114 // import "github.com/fatih/color" 115 // import "github.com/mattn/go-colorable" 116 117 out := colorable.NewColorable(os.Stdout) // needed for Windows 118 enc = json.NewEncoder(out) 119 120 fclrs := fatihcolor.DefaultColors() 121 // Change some values, just for fun 122 fclrs.Number = color.New(color.FgBlue) 123 fclrs.String = color.New(color.FgCyan) 124 125 clrs := fatihcolor.ToCoreColors(fclrs) 126 enc.SetColors(clrs) 127 ``` 128 129 ### Drop-in for `encoding/json` 130 131 This package is a full drop-in for stdlib [`encoding/json`](https://pkg.go.dev/encoding/json) 132 (thanks to the ancestral [`segmentio/encoding/json`](https://pkg.go.dev/github.com/segmentio/encoding/json) 133 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 ## Example app: `jc` 142 143 See [`cmd/jc`](cmd/jc/main.go) for a trivial CLI implementation that can accept JSON input, 144 and output that JSON in color. 145 146 ```shell 147 # From project root 148 $ go install ./cmd/jc 149 $ cat ./testdata/sakila_actor.json | jc 150 ``` 151 152 ## Benchmarks 153 154 Note that this package contains [`golang_bench_test.go`](./golang_bench_test.go), which 155 is inherited from `segmentj`. But here we're interested in [`benchmark_test.go:BenchmarkEncode`](./benchmark_test.go), 156 which benchmarks encoding performance versus other JSON encoder packages. 157 The results below benchmark the following: 158 159 - Stdlib [`encoding/json`](https://pkg.go.dev/encoding/json) (`go1.17.1`). 160 - [`segmentj`](https://github.com/segmentio/encoding): `v0.1.14`, which was when `jsoncolor` was forked. The newer `segmentj` code performs even better. 161 - `neilotoole/jsoncolor`: (this package) `v0.6.0`. 162 - [`nwidger/jsoncolor`](https://github.com/nwidger/jsoncolor): `v0.3.0`, latest at time of benchmarks. 163 164 Note that two other Go JSON colorization packages ([`hokaccha/go-prettyjson`](https://github.com/hokaccha/go-prettyjson) and 165 [`TylerBrock/colorjson`](https://github.com/TylerBrock/colorjson)) are excluded from 166 these benchmarks because they do not provide a stdlib-compatible `Encoder` impl. 167 168 ``` 169 $ go test -bench=BenchmarkEncode -benchtime="5s" 170 goarch: amd64 171 pkg: github.com/neilotoole/jsoncolor 172 cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz 173 BenchmarkEncode/stdlib_NoIndent-16 181 33047390 ns/op 8870685 B/op 120022 allocs/op 174 BenchmarkEncode/stdlib_Indent-16 124 48093178 ns/op 10470366 B/op 120033 allocs/op 175 BenchmarkEncode/segmentj_NoIndent-16 415 14658699 ns/op 3788911 B/op 10020 allocs/op 176 BenchmarkEncode/segmentj_Indent-16 195 30628798 ns/op 5404492 B/op 10025 allocs/op 177 BenchmarkEncode/neilotoole_NoIndent_NoColor-16 362 16522399 ns/op 3789034 B/op 10020 allocs/op 178 BenchmarkEncode/neilotoole_Indent_NoColor-16 303 20146856 ns/op 5460753 B/op 10021 allocs/op 179 BenchmarkEncode/neilotoole_NoIndent_Color-16 295 19989420 ns/op 10326019 B/op 10029 allocs/op 180 BenchmarkEncode/neilotoole_Indent_Color-16 246 24714163 ns/op 11996890 B/op 10030 allocs/op 181 BenchmarkEncode/nwidger_NoIndent_NoColor-16 10 541107983 ns/op 92934231 B/op 4490210 allocs/op 182 BenchmarkEncode/nwidger_Indent_NoColor-16 7 798088086 ns/op 117258321 B/op 6290213 allocs/op 183 BenchmarkEncode/nwidger_indent_NoIndent_Colo-16 10 542002051 ns/op 92935639 B/op 4490224 allocs/op 184 BenchmarkEncode/nwidger_indent_Indent_Color-16 7 799928353 ns/op 117259195 B/op 6290220 allocs/op 185 ``` 186 187 As always, take benchmarks with a large grain of salt, as they're based on a (small) synthetic benchmark. 188 More benchmarks would give a better picture (and note as well that the benchmarked `segmentj` is an older version, `v0.1.14`). 189 190 All that having been said, what can we surmise from these particular results? 191 192 - `segmentj` performs better than `stdlib` at all encoding tasks. 193 - `jsoncolor` performs better than `segmentj` for indentation (which makes sense, as indentation is performed inline). 194 - `jsoncolor` performs better than `stdlib` at all encoding tasks. 195 196 Again, trust these benchmarks at your peril. Create your own benchmarks for your own workload. 197 198 ## Notes 199 200 - The [`.golangci.yml`](./.golangci.yml) linter settings have been fiddled with to hush some 201 linting issues inherited from the `segmentio` codebase at the time of forking. Thus, the linter report 202 may not be of great use. In an ideal world, the `jsoncolor` functionality would be [ported](https://github.com/neilotoole/jsoncolor/issues/15) to a 203 more recent (and better-linted) version of the `segementio` codebase. 204 - The `segmentio` encoder (at least as of `v0.1.14`) encodes `time.Duration` as string, while `stdlib` outputs as `int64`. 205 This package follows `stdlib`. 206 - The [`Colors.Punc`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#Colors) field controls all 207 punctuation colorization, i.e. `[]{},:"`. It is probably worthwhile to [separate](https://github.com/neilotoole/jsoncolor/issues/16) 208 these out into individually-configurable elements. 209 210 <a name="history"></a> 211 ## CHANGELOG 212 213 History: this package is an extract of [`sq`](https://github.com/neilotoole/sq)'s JSON encoding package, which itself is a fork of the 214 [`segmentio/encoding`](https://github.com/segmentio/encoding) JSON encoding package. Note that the 215 original `sq` JSON encoder was forked from Segment's codebase at `v0.1.14`, so 216 the codebases have drifted significantly by now. 217 218 ### [v0.7.1](https://github.com/neilotoole/jsoncolor/releases/tag/v0.7.1) 219 220 - [#27](https://github.com/neilotoole/jsoncolor/pull/27): Improved Windows terminal color support checking. 221 222 ### [v0.7.0](https://github.com/neilotoole/jsoncolor/releases/tag/v0.7.0) 223 224 - [#21](https://github.com/neilotoole/jsoncolor/pull/21): Support for [`encoding.TextMarshaler`](https://pkg.go.dev/encoding#TextMarshaler). 225 - [#22](https://github.com/neilotoole/jsoncolor/pull/22): Removed redundant dependencies. 226 - [#26](https://github.com/neilotoole/jsoncolor/pull/26): Updated dependencies. 227 228 ## Acknowledgments 229 230 - [`jq`](https://stedolan.github.io/jq/): sine qua non. 231 - [`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. 232 - [`sq`](https://github.com/neilotoole/sq): `jsoncolor` is effectively an extract of code created specifically for `sq`. 233 - [`mattn/go-colorable`](https://github.com/mattn/go-colorable): no project is complete without `mattn` having played a role. 234 - [`fatih/color`](https://github.com/fatih/color): the color library. 235 - [`@hermannm`](https://github.com/hermannm): for several PRs. 236 237 ### Related 238 239 - [`nwidger/jsoncolor`](https://github.com/nwidger/jsoncolor) 240 - [`hokaccha/go-prettyjson`](https://github.com/hokaccha/go-prettyjson) 241 - [`TylerBrock/colorjson`](https://github.com/TylerBrock/colorjson)