Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Add toggle to allow log lines to be JSON colorized #1778

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ K9s uses aliases to navigate most K8s resources.
textWrap: false
# Toggles log line timestamp info. Default false
showTime: false
# Toggles whether JSON log lines should be colorized. Default false
showJSON: false
# Indicates the current kube context. Defaults to current context
currentContext: minikube
# Indicates the current kube cluster. Defaults to current context cluster
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ require (
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/rm-hull/colorjson v0.0.0-20220923220430-b50ee91dc6f6 // indirect
github.com/rubenv/sql-migrate v1.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ github.com/rakyll/hey v0.1.4/go.mod h1:nAOTOo+L52KB9SZq/M6J18kxjto4yVtXQDjU2HgjU
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rm-hull/colorjson v0.0.0-20220923220430-b50ee91dc6f6 h1:avrA8y9AJF9WtGipEvrM8I/7XoKcxEk30659rPHJlnM=
github.com/rm-hull/colorjson v0.0.0-20220923220430-b50ee91dc6f6/go.mod h1:tJTNxpJk1e15vd8WY5lsj9Tq5vjdnNz3YAbCwxYskBs=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
Expand Down
2 changes: 2 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ var expectedConfig = `k9s:
fullScreenLogs: false
textWrap: false
showTime: false
showJSON: false
currentContext: blee
currentCluster: blee
clusters:
Expand Down Expand Up @@ -393,6 +394,7 @@ var resetConfig = `k9s:
fullScreenLogs: false
textWrap: false
showTime: false
showJSON: false
currentContext: blee
currentCluster: blee
clusters:
Expand Down
1 change: 1 addition & 0 deletions internal/config/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Logger struct {
FullScreenLogs bool `yaml:"fullScreenLogs"`
TextWrap bool `yaml:"textWrap"`
ShowTime bool `yaml:"showTime"`
ShowJSON bool `yaml:"showJSON"`
}

// NewLogger returns a new instance.
Expand Down
29 changes: 24 additions & 5 deletions internal/dao/log_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package dao

import (
"bytes"
"encoding/json"

"github.com/rm-hull/colorjson"
)

// LogChan represents a channel for logs.
Expand Down Expand Up @@ -64,7 +67,7 @@ func (l *LogItem) Size() int {
}

// Render returns a log line as string.
func (l *LogItem) Render(paint string, showTime bool, bb *bytes.Buffer) {
func (l *LogItem) Render(paint string, showTime bool, showJson bool, bb *bytes.Buffer) {
index := bytes.Index(l.Bytes, []byte{' '})
if showTime && index > 0 {
bb.WriteString("[gray::b]")
Expand All @@ -89,9 +92,25 @@ func (l *LogItem) Render(paint string, showTime bool, bb *bytes.Buffer) {
bb.WriteString("[-::] ")
}

if index > 0 {
bb.Write(l.Bytes[index+1:])
} else {
bb.Write(l.Bytes)
bb.Write(colorizeJSON(l.Bytes[index+1:], showJson))
}

func colorizeJSON(text []byte, showJson bool) []byte {
if !showJson {
return text
}
var obj map[string]interface{}
rm-hull marked this conversation as resolved.
Show resolved Hide resolved
err := json.Unmarshal(text, &obj)
if err != nil {
return text
}
f := colorjson.NewFormatter()
f.Indent = 0
f.ObjectSeparator = false

s, err := f.Marshal(obj)
if err != nil {
return text
rm-hull marked this conversation as resolved.
Show resolved Hide resolved
}
return append(s, '\n')
}
6 changes: 3 additions & 3 deletions internal/dao/log_item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func TestLogItemRender(t *testing.T) {
i.Pod, i.Container = n, u.opts.Container

bb := bytes.NewBuffer(make([]byte, 0, i.Size()))
i.Render("yellow", u.opts.ShowTimestamp, bb)
i.Render("yellow", u.opts.ShowTimestamp, u.opts.ShowJSON, bb)
assert.Equal(t, u.e, bb.String())
})
}
Expand All @@ -100,7 +100,7 @@ func BenchmarkLogItemRender(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
bb := bytes.NewBuffer(make([]byte, 0, i.Size()))
i.Render("yellow", true, bb)
i.Render("yellow", true, false, bb)
}
}

Expand All @@ -113,6 +113,6 @@ func BenchmarkLogItemRenderNoTS(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
bb := bytes.NewBuffer(make([]byte, 0, i.Size()))
i.Render("yellow", false, bb)
i.Render("yellow", false, false, bb)
}
}
26 changes: 13 additions & 13 deletions internal/dao/log_items.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (l *LogItems) Add(ii ...*LogItem) {
}

// Lines returns a collection of log lines.
func (l *LogItems) Lines(index int, showTime bool, ll [][]byte) {
func (l *LogItems) Lines(index int, showTime bool, showJson bool, ll [][]byte) {
l.mx.Lock()
defer l.mx.Unlock()

Expand All @@ -118,28 +118,28 @@ func (l *LogItems) Lines(index int, showTime bool, ll [][]byte) {
colorIndex++
}
bb := bytes.NewBuffer(make([]byte, 0, item.Size()))
item.Render(color, showTime, bb)
item.Render(color, showTime, showJson, bb)
ll[i] = bb.Bytes()
}
}

// StrLines returns a collection of log lines.
func (l *LogItems) StrLines(index int, showTime bool) []string {
func (l *LogItems) StrLines(index int, showTime bool, showJson bool) []string {
l.mx.Lock()
defer l.mx.Unlock()

ll := make([]string, len(l.items[index:]))
for i, item := range l.items[index:] {
bb := bytes.NewBuffer(make([]byte, 0, item.Size()))
item.Render("white", showTime, bb)
item.Render("white", showTime, showJson, bb)
ll[i] = bb.String()
}

return ll
}

// Render returns logs as a collection of strings.
func (l *LogItems) Render(index int, showTime bool, ll [][]byte) {
func (l *LogItems) Render(index int, showTime bool, showJson bool, ll [][]byte) {
var colorIndex int
for i, item := range l.items[index:] {
id := item.ID()
Expand All @@ -153,7 +153,7 @@ func (l *LogItems) Render(index int, showTime bool, ll [][]byte) {
colorIndex++
}
bb := bytes.NewBuffer(make([]byte, 0, item.Size()))
item.Render(color, showTime, bb)
item.Render(color, showTime, showJson, bb)
ll[i] = bb.Bytes()
}
}
Expand All @@ -167,26 +167,26 @@ func (l *LogItems) DumpDebug(m string) {
}

// Filter filters out log items based on given filter.
func (l *LogItems) Filter(index int, q string, showTime bool) ([]int, [][]int, error) {
func (l *LogItems) Filter(index int, q string, showTime bool, showJson bool) ([]int, [][]int, error) {
if q == "" {
return nil, nil, nil
}
if IsFuzzySelector(q) {
mm, ii := l.fuzzyFilter(index, strings.TrimSpace(q[2:]), showTime)
mm, ii := l.fuzzyFilter(index, strings.TrimSpace(q[2:]), showTime, showJson)
return mm, ii, nil
}
matches, indices, err := l.filterLogs(index, q, showTime)
matches, indices, err := l.filterLogs(index, q, showTime, showJson)
if err != nil {
return nil, nil, err
}

return matches, indices, nil
}

func (l *LogItems) fuzzyFilter(index int, q string, showTime bool) ([]int, [][]int) {
func (l *LogItems) fuzzyFilter(index int, q string, showTime bool, showJson bool) ([]int, [][]int) {
q = strings.TrimSpace(q)
matches, indices := make([]int, 0, len(l.items)), make([][]int, 0, 10)
mm := fuzzy.Find(q, l.StrLines(index, showTime))
mm := fuzzy.Find(q, l.StrLines(index, showTime, showJson))
for _, m := range mm {
matches = append(matches, m.Index)
indices = append(indices, m.MatchedIndexes)
Expand All @@ -195,7 +195,7 @@ func (l *LogItems) fuzzyFilter(index int, q string, showTime bool) ([]int, [][]i
return matches, indices
}

func (l *LogItems) filterLogs(index int, q string, showTime bool) ([]int, [][]int, error) {
func (l *LogItems) filterLogs(index int, q string, showTime bool, showJson bool) ([]int, [][]int, error) {
var invert bool
if IsInverseSelector(q) {
invert = true
Expand All @@ -207,7 +207,7 @@ func (l *LogItems) filterLogs(index int, q string, showTime bool) ([]int, [][]in
}
matches, indices := make([]int, 0, len(l.items)), make([][]int, 0, 10)
ll := make([][]byte, len(l.items[index:]))
l.Lines(index, showTime, ll)
l.Lines(index, showTime, showJson, ll)
for i, line := range ll {
locs := rx.FindIndex(line)
if locs != nil && invert {
Expand Down
4 changes: 2 additions & 2 deletions internal/dao/log_items_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestLogItemsFilter(t *testing.T) {
for _, i := range ii.Items() {
i.Pod, i.Container = n, u.opts.Container
}
res, _, err := ii.Filter(0, u.q, false)
res, _, err := ii.Filter(0, u.q, false, false)
assert.Equal(t, u.err, err)
if err == nil {
assert.Equal(t, u.e, res)
Expand Down Expand Up @@ -121,7 +121,7 @@ func TestLogItemsRender(t *testing.T) {
ii.Items()[0].Pod, ii.Items()[0].Container = n, u.opts.Container
t.Run(k, func(t *testing.T) {
res := make([][]byte, 1)
ii.Render(0, u.opts.ShowTimestamp, res)
ii.Render(0, u.opts.ShowTimestamp, u.opts.ShowJSON, res)
assert.Equal(t, u.e, string(res[0]))
})
}
Expand Down
1 change: 1 addition & 0 deletions internal/dao/log_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type LogOptions struct {
SingleContainer bool
MultiPods bool
ShowTimestamp bool
ShowJSON bool
AllContainers bool
}

Expand Down
20 changes: 13 additions & 7 deletions internal/model/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ func (l *Log) ToggleShowTimestamp(b bool) {
l.Refresh()
}

// ToggleShowJSON toggles to colorize JSON logs.
func (l *Log) ToggleShowJSON(b bool) {
l.logOptions.ShowJSON = b
l.Refresh()
}

func (l *Log) Head(ctx context.Context) {
l.mx.Lock()
{
Expand Down Expand Up @@ -146,7 +152,7 @@ func (l *Log) Clear() {
func (l *Log) Refresh() {
l.fireLogCleared()
ll := make([][]byte, l.lines.Len())
l.lines.Render(0, l.logOptions.ShowTimestamp, ll)
l.lines.Render(0, l.logOptions.ShowTimestamp, l.logOptions.ShowJSON, ll)
l.fireLogChanged(ll)
}

Expand Down Expand Up @@ -181,7 +187,7 @@ func (l *Log) Set(lines *dao.LogItems) {

l.fireLogCleared()
ll := make([][]byte, l.lines.Len())
l.lines.Render(0, l.logOptions.ShowTimestamp, ll)
l.lines.Render(0, l.logOptions.ShowTimestamp, l.logOptions.ShowJSON, ll)
l.fireLogChanged(ll)
}

Expand All @@ -195,7 +201,7 @@ func (l *Log) ClearFilter() {

l.fireLogCleared()
ll := make([][]byte, l.lines.Len())
l.lines.Render(0, l.logOptions.ShowTimestamp, ll)
l.lines.Render(0, l.logOptions.ShowTimestamp, l.logOptions.ShowJSON, ll)
l.fireLogChanged(ll)
}

Expand Down Expand Up @@ -347,15 +353,15 @@ func (l *Log) applyFilter(index int, q string) ([][]byte, error) {
if q == "" {
return nil, nil
}
matches, indices, err := l.lines.Filter(index, q, l.logOptions.ShowTimestamp)
matches, indices, err := l.lines.Filter(index, q, l.logOptions.ShowTimestamp, l.logOptions.ShowJSON)
if err != nil {
return nil, err
}

// No filter!
if matches == nil {
ll := make([][]byte, l.lines.Len())
l.lines.Render(index, l.logOptions.ShowTimestamp, ll)
l.lines.Render(index, l.logOptions.ShowTimestamp, l.logOptions.ShowJSON, ll)
return ll, nil
}
// Blank filter
Expand All @@ -364,7 +370,7 @@ func (l *Log) applyFilter(index int, q string) ([][]byte, error) {
}
filtered := make([][]byte, 0, len(matches))
ll := make([][]byte, l.lines.Len())
l.lines.Lines(index, l.logOptions.ShowTimestamp, ll)
l.lines.Lines(index, l.logOptions.ShowTimestamp, l.logOptions.ShowJSON, ll)
for i, idx := range matches {
filtered = append(filtered, color.Highlight(ll[idx], indices[i], 209))
}
Expand All @@ -375,7 +381,7 @@ func (l *Log) applyFilter(index int, q string) ([][]byte, error) {
func (l *Log) fireLogBuffChanged(index int) {
ll := make([][]byte, l.lines.Len()-index)
if l.filter == "" {
l.lines.Render(index, l.logOptions.ShowTimestamp, ll)
l.lines.Render(index, l.logOptions.ShowTimestamp, l.logOptions.ShowJSON, ll)
} else {
ff, err := l.applyFilter(index, l.filter)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions internal/model/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestLogBasic(t *testing.T) {
assert.Equal(t, 1, v.clearCalled)
assert.Equal(t, 0, v.errCalled)
ll := make([][]byte, data.Len())
data.Lines(0, false, ll)
data.Lines(0, false, false, ll)
assert.Equal(t, ll, v.data)
}

Expand All @@ -168,7 +168,7 @@ func TestLogAppend(t *testing.T) {
items.Add(dao.NewLogItemFromString("blah blah"))
m.Set(items)
ll := make([][]byte, items.Len())
items.Lines(0, false, ll)
items.Lines(0, false, false, ll)
assert.Equal(t, ll, v.data)

data := dao.NewLogItems()
Expand All @@ -181,7 +181,7 @@ func TestLogAppend(t *testing.T) {
}
assert.Equal(t, 1, v.dataCalled)
ll = make([][]byte, items.Len())
items.Lines(0, false, ll)
items.Lines(0, false, false, ll)
assert.Equal(t, ll, v.data)

m.Notify()
Expand Down
1 change: 1 addition & 0 deletions internal/view/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func (c *Container) logOptions(prev bool) (*dao.LogOptions, error) {
SinceSeconds: cfg.SinceSeconds,
SingleContainer: true,
ShowTimestamp: cfg.ShowTime,
ShowJSON: cfg.ShowJSON,
Previous: prev,
}

Expand Down
1 change: 1 addition & 0 deletions internal/view/dp.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func (d *Deploy) logOptions(prev bool) (*dao.LogOptions, error) {
SingleContainer: len(cc) == 1,
AllContainers: allCos,
ShowTimestamp: cfg.ShowTime,
ShowJSON: cfg.ShowJSON,
Previous: prev,
}
if co == "" {
Expand Down
Loading