diff --git a/cmd/kail/main.go b/cmd/kail/main.go index b8f17ec..18e6d8f 100644 --- a/cmd/kail/main.go +++ b/cmd/kail/main.go @@ -46,7 +46,7 @@ var ( flagNode = kingpin.Flag("node", "node").PlaceHolder("NAME").Strings() flagIng = kingpin.Flag("ing", "ingress").PlaceHolder("NAME").Strings() - flagOutput = kingpin.Flag("output", "Log output mode (default, raw, or json)"). + flagOutput = kingpin.Flag("output", "Log output mode (default, raw, json, or json-pretty)"). Short('o'). PlaceHolder("default"). Default("default"). @@ -324,6 +324,8 @@ func streamLogs(controller kail.Controller) { writer = kail.NewWriter(os.Stdout) case "json": writer = kail.NewJSONWriter(os.Stdout) + case "json-pretty": + writer = kail.NewJSONPrettyWriter(os.Stdout) case "raw": writer = kail.NewRawWriter(os.Stdout) default: diff --git a/writer.go b/writer.go index a3ef5e5..8234e56 100644 --- a/writer.go +++ b/writer.go @@ -1,6 +1,7 @@ package kail import ( + "encoding/json" "fmt" "io" @@ -25,7 +26,23 @@ func NewRawWriter(out io.Writer) Writer { } func NewJSONWriter(out io.Writer) Writer { - return &writerJSON{out} + return &writerJSON{ + out: out, + getEnc: func(o io.Writer) *json.Encoder { + return json.NewEncoder(o) + }, + } +} + +func NewJSONPrettyWriter(out io.Writer) Writer { + return &writerJSON{ + out: out, + getEnc: func(o io.Writer) *json.Encoder { + e := json.NewEncoder(o) + e.SetIndent("", " ") + return e + }, + } } type writer struct { @@ -80,7 +97,8 @@ func (w *writerRaw) Fprint(out io.Writer, ev Event) error { } type writerJSON struct { - out io.Writer + out io.Writer + getEnc func(io.Writer) *json.Encoder } func (w *writerJSON) Print(ev Event) error { @@ -90,26 +108,27 @@ func (w *writerJSON) Print(ev Event) error { func (w *writerJSON) Fprint(out io.Writer, ev Event) error { log := ev.Log() - if sz := len(log); sz == 0 || log[sz-1] == byte('\n') { log = log[:sz-1] } - if log[0] != '{' && log[0] != '[' { - log = append([]byte{'"'}, log...) - log = append(log, '"') + enc := w.getEnc(out) + + data := map[string]interface{}{ + "namespace": ev.Source().Namespace(), + "name": ev.Source().Name(), + "container": ev.Source().Container(), } - if _, err := fmt.Fprintf(out, - `{"namespace":"%s","pod":"%s","container":"%s","message":%s}%s`, - ev.Source().Namespace(), - ev.Source().Name(), - ev.Source().Container(), - log, - "\n", - ); err != nil { - return err + messageMap := map[string]interface{}{} + if err := json.Unmarshal(log, &messageMap); err != nil { + data["message"] = string(log) + } else { + data["message"] = messageMap } + if err := enc.Encode(data); err != nil { + return err + } return nil }