provides logger config options. Fix #623

mine
derailed 2020-03-14 10:30:21 -06:00
parent 2e05367256
commit 3efb3f2596
11 changed files with 133 additions and 54 deletions

5
go.sum
View File

@ -4,6 +4,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
@ -37,6 +38,7 @@ github.com/Masterminds/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+B
github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU=
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/hcsshim v0.0.0-20190417211021-672e52e9209d/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
@ -97,6 +99,7 @@ github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
github.com/containerd/containerd v1.3.0-beta.2.0.20190823190603-4a2f61c4f2b4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
@ -320,6 +323,7 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@ -337,6 +341,7 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=

View File

@ -199,6 +199,9 @@ func (c *Config) Load(path string) error {
if cfg.K9s != nil {
c.K9s = cfg.K9s
}
if c.K9s.Logger == nil {
c.K9s.Logger = NewLogger()
}
return nil
}

View File

@ -96,7 +96,8 @@ func TestConfigLoad(t *testing.T) {
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
assert.Equal(t, 2, cfg.K9s.RefreshRate)
assert.Equal(t, 200, cfg.K9s.LogBufferSize)
assert.Equal(t, 2000, cfg.K9s.Logger.BufferSize)
assert.Equal(t, 200, cfg.K9s.Logger.TailCount)
assert.Equal(t, "minikube", cfg.K9s.CurrentContext)
assert.Equal(t, "minikube", cfg.K9s.CurrentCluster)
assert.NotNil(t, cfg.K9s.Clusters)
@ -206,8 +207,8 @@ func TestConfigSaveFile(t *testing.T) {
assert.Nil(t, cfg.Load("testdata/k9s.yml"))
cfg.K9s.RefreshRate = 100
cfg.K9s.ReadOnly = true
cfg.K9s.LogBufferSize = 500
cfg.K9s.LogRequestSize = 100
cfg.K9s.Logger.TailCount = 500
cfg.K9s.Logger.BufferSize = 800
cfg.K9s.CurrentContext = "blee"
cfg.K9s.CurrentCluster = "blee"
cfg.Validate()
@ -262,8 +263,9 @@ var expectedConfig = `k9s:
refreshRate: 100
headless: false
readOnly: true
logBufferSize: 500
logRequestSize: 100
logger:
tail: 500
buffer: 800
currentContext: blee
currentCluster: blee
fullScreenLogs: false
@ -310,8 +312,9 @@ var resetConfig = `k9s:
refreshRate: 2
headless: false
readOnly: false
logBufferSize: 200
logRequestSize: 200
logger:
tail: 200
buffer: 2000
currentContext: blee
currentCluster: blee
fullScreenLogs: false

View File

@ -3,10 +3,8 @@ package config
import "github.com/derailed/k9s/internal/client"
const (
defaultRefreshRate = 2
defaultLogRequestSize = 200
defaultLogBufferSize = 1000
defaultReadOnly = false
defaultRefreshRate = 2
defaultReadOnly = false
)
// K9s tracks K9s configuration options.
@ -14,8 +12,7 @@ type K9s struct {
RefreshRate int `yaml:"refreshRate"`
Headless bool `yaml:"headless"`
ReadOnly bool `yaml:"readOnly"`
LogBufferSize int `yaml:"logBufferSize"`
LogRequestSize int `yaml:"logRequestSize"`
Logger *Logger `yaml:"logger"`
CurrentContext string `yaml:"currentContext"`
CurrentCluster string `yaml:"currentCluster"`
FullScreenLogs bool `yaml:"fullScreenLogs"`
@ -30,12 +27,11 @@ type K9s struct {
// NewK9s create a new K9s configuration.
func NewK9s() *K9s {
return &K9s{
RefreshRate: defaultRefreshRate,
ReadOnly: defaultReadOnly,
LogBufferSize: defaultLogBufferSize,
LogRequestSize: defaultLogRequestSize,
Clusters: make(map[string]*Cluster),
Thresholds: NewThreshold(),
RefreshRate: defaultRefreshRate,
ReadOnly: defaultReadOnly,
Logger: NewLogger(),
Clusters: make(map[string]*Cluster),
Thresholds: NewThreshold(),
}
}
@ -106,14 +102,6 @@ func (k *K9s) validateDefaults() {
if k.RefreshRate <= 0 {
k.RefreshRate = defaultRefreshRate
}
if k.LogBufferSize <= 0 {
k.LogBufferSize = defaultLogBufferSize
}
if k.LogRequestSize <= 0 {
k.LogRequestSize = defaultLogRequestSize
}
}
func (k *K9s) checkClusters(ks KubeSettings) {
@ -140,6 +128,11 @@ func (k *K9s) Validate(c client.Connection, ks KubeSettings) {
}
k.checkClusters(ks)
if k.Logger == nil {
k.Logger = NewLogger()
} else {
k.Logger.Validate(c, ks)
}
if k.Thresholds == nil {
k.Thresholds = NewThreshold()
}

View File

@ -22,8 +22,8 @@ func TestK9sValidate(t *testing.T) {
c.Validate(mc, mk)
assert.Equal(t, 2, c.RefreshRate)
assert.Equal(t, 1000, c.LogBufferSize)
assert.Equal(t, 200, c.LogRequestSize)
assert.Equal(t, 50, c.Logger.TailCount)
assert.Equal(t, 1_000, c.Logger.BufferSize)
assert.Equal(t, "ctx1", c.CurrentContext)
assert.Equal(t, "c1", c.CurrentCluster)
assert.Equal(t, 1, len(c.Clusters))
@ -45,8 +45,8 @@ func TestK9sValidateBlank(t *testing.T) {
c.Validate(mc, mk)
assert.Equal(t, 2, c.RefreshRate)
assert.Equal(t, 1000, c.LogBufferSize)
assert.Equal(t, 200, c.LogRequestSize)
assert.Equal(t, 50, c.Logger.TailCount)
assert.Equal(t, 1_000, c.Logger.BufferSize)
assert.Equal(t, "ctx1", c.CurrentContext)
assert.Equal(t, "c1", c.CurrentCluster)
assert.Equal(t, 1, len(c.Clusters))

44
internal/config/logger.go Normal file
View File

@ -0,0 +1,44 @@
package config
import (
"github.com/derailed/k9s/internal/client"
)
const (
// DefaultLoggerTailCount tracks log tail size.
DefaultLoggerTailCount = 50
// DefaultLoggerBufferSize tracks the buffer size.
DefaultLoggerBufferSize = 1_000
// MaxLogThreshold sets the max value for log size.
MaxLogThreshold = 5_000
)
// Logger tracks logger options
type Logger struct {
TailCount int `yaml:"tail"`
BufferSize int `yaml:"buffer"`
}
// NewLogger returns a new instance.
func NewLogger() *Logger {
return &Logger{
TailCount: DefaultLoggerTailCount,
BufferSize: DefaultLoggerBufferSize,
}
}
// Validate checks thresholds and make sure we're cool. If not use defaults.
func (l *Logger) Validate(_ client.Connection, _ KubeSettings) {
if l.TailCount <= 0 {
l.TailCount = DefaultLoggerTailCount
}
if l.TailCount > MaxLogThreshold {
l.TailCount = MaxLogThreshold
}
if l.BufferSize <= 0 {
l.BufferSize = DefaultLoggerBufferSize
}
if l.BufferSize > MaxLogThreshold {
l.BufferSize = MaxLogThreshold
}
}

View File

@ -0,0 +1,24 @@
package config_test
import (
"testing"
"github.com/derailed/k9s/internal/config"
"github.com/stretchr/testify/assert"
)
func TestNewLogger(t *testing.T) {
l := config.NewLogger()
l.Validate(nil, nil)
assert.Equal(t, 50, l.TailCount)
assert.Equal(t, 1_000, l.BufferSize)
}
func TestLoggerValidate(t *testing.T) {
var l config.Logger
l.Validate(nil, nil)
assert.Equal(t, 50, l.TailCount)
assert.Equal(t, 1_000, l.BufferSize)
}

View File

@ -1,7 +1,8 @@
k9s:
refreshRate: 2
logBufferSize: 200
logRequestSize: 200
logger:
tail: 200
buffer: 2000
currentContext: minikube
currentCluster: minikube
clusters:

View File

@ -10,13 +10,12 @@ import (
"github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/dao"
"github.com/rs/zerolog/log"
"github.com/sahilm/fuzzy"
)
const logMaxBufferSize = 100
// LogsListener represents a log model listener.
type LogsListener interface {
// LogChanged notifies the model changed.
@ -39,21 +38,27 @@ type Log struct {
cancelFn context.CancelFunc
mx sync.RWMutex
filter string
bufferSize int
lastSent int
showTimestamp bool
timeOut time.Duration
flushTimeout time.Duration
}
// NewLog returns a new model.
func NewLog(gvr client.GVR, opts dao.LogOptions, timeOut time.Duration) *Log {
func NewLog(gvr client.GVR, opts dao.LogOptions, flushTimeout time.Duration) *Log {
return &Log{
gvr: gvr,
logOptions: opts,
lines: nil,
timeOut: timeOut,
gvr: gvr,
logOptions: opts,
lines: nil,
flushTimeout: flushTimeout,
}
}
// Configure sets logger configuration.
func (l *Log) Configure(opts *config.Logger) {
l.bufferSize, l.logOptions.Lines = opts.BufferSize, int64(opts.TailCount)
}
// GetPath returns resource path.
func (l *Log) GetPath() string { return l.logOptions.Path }
@ -217,13 +222,13 @@ func (l *Log) updateLogs(ctx context.Context, c <-chan []byte) {
var overflow bool
l.mx.RLock()
{
overflow = len(l.lines)-l.lastSent > logMaxBufferSize
overflow = len(l.lines)-l.lastSent > l.bufferSize
}
l.mx.RUnlock()
if overflow {
l.Notify(true)
}
case <-time.After(l.timeOut):
case <-time.After(l.flushTimeout):
l.Notify(true)
case <-ctx.Done():
return

View File

@ -74,7 +74,7 @@ func (c *Configurator) RefreshCustomViews() {
}
if err := c.CustomView.Load(config.K9sViewConfigFile); err != nil {
log.Debug().Msgf("No view custom configuration file found -- %s", config.K9sViewConfigFile)
log.Error().Err(err).Msgf("Custom view load failed %s", config.K9sViewConfigFile)
return
}
}

View File

@ -20,14 +20,11 @@ import (
)
const (
logTitle = "logs"
logMessage = "[:orange:b]Waiting for logs...[::]"
logCoFmt = " Logs([fg:bg:]%s:[hilite:bg:b]%s[-:bg:-]) "
logFmt = " Logs([fg:bg:]%s) "
// BOZO!! Canned! Need config tail line counts!
tailLineCount = 50
defaultTimeout = 200 * time.Millisecond
logTitle = "logs"
logMessage = "[:orange:b]Waiting for logs...[::]"
logCoFmt = " Logs([fg:bg:]%s:[hilite:bg:b]%s[-:bg:-]) "
logFmt = " Logs([fg:bg:]%s) "
flushTimeout = 200 * time.Millisecond
)
// Log represents a generic log viewer.
@ -40,6 +37,7 @@ type Log struct {
ansiWriter io.Writer
cmdBuff *ui.CmdBuff
model *model.Log
counts int
}
var _ model.Component = (*Log)(nil)
@ -49,7 +47,7 @@ func NewLog(gvr client.GVR, path, co string, prev bool) *Log {
l := Log{
Flex: tview.NewFlex(),
cmdBuff: ui.NewCmdBuff('/', ui.FilterBuff),
model: model.NewLog(gvr, buildLogOpts(path, co, prev, true, tailLineCount), defaultTimeout),
model: model.NewLog(gvr, buildLogOpts(path, co, prev, true, config.DefaultLoggerTailCount), flushTimeout),
}
return &l
@ -60,6 +58,8 @@ func (l *Log) Init(ctx context.Context) (err error) {
if l.app, err = extractApp(ctx); err != nil {
return err
}
l.model.Configure(l.app.Config.K9s.Logger)
l.SetBorder(true)
l.SetBorderPadding(0, 0, 1, 1)
l.SetDirection(tview.FlexRow)
@ -74,7 +74,7 @@ func (l *Log) Init(ctx context.Context) (err error) {
}
l.logs.SetText(logMessage)
l.logs.SetWrap(false)
l.logs.SetMaxBuffer(l.app.Config.K9s.LogBufferSize)
l.logs.SetMaxBuffer(l.app.Config.K9s.Logger.BufferSize)
l.ansiWriter = tview.ANSIWriter(l.logs, l.app.Styles.Views().Log.FgColor.String(), l.app.Styles.Views().Log.BgColor.String())
l.AddItem(l.logs, 0, 1, true)
@ -97,6 +97,7 @@ func (l *Log) Init(ctx context.Context) (err error) {
// LogCleared clears the logs.
func (l *Log) LogCleared() {
l.counts = 0
l.app.QueueUpdateDraw(func() {
l.logs.Clear()
l.logs.ScrollTo(0, 0)