github.com/neilotoole/jsoncolor@v0.6.0/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.6.0-green.svg)](https://github.com/neilotoole/jsoncolor/releases/tag/v0.6.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 `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  ![jsoncolor-output](https://github.com/neilotoole/jsoncolor/wiki/images/jsoncolor-example-output2.png)
    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)