fix #776
parent
5c214ccda4
commit
5bbc159df9
|
|
@ -1,4 +1,5 @@
|
|||
.vscode
|
||||
*.out
|
||||
.idea
|
||||
.envrc
|
||||
cov.out
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ func NewLogItem(b []byte) *LogItem {
|
|||
|
||||
// NewLogItemFromString returns a new item.
|
||||
func NewLogItemFromString(s string) *LogItem {
|
||||
l := LogItem{Bytes: []byte(s)}
|
||||
l.Timestamp = time.Now().String()
|
||||
|
||||
return &l
|
||||
return &LogItem{
|
||||
Bytes: []byte(s),
|
||||
Timestamp: time.Now().String(),
|
||||
}
|
||||
}
|
||||
|
||||
// ID returns pod and or container based id.
|
||||
|
|
@ -125,15 +125,15 @@ func (l LogItems) Lines() []string {
|
|||
|
||||
// Render returns logs as a collection of strings.
|
||||
func (l LogItems) Render(showTime bool, ll [][]byte) {
|
||||
colors := map[string]int{}
|
||||
colors := make(map[string]int, len(l))
|
||||
for i, item := range l {
|
||||
info := item.ID()
|
||||
c, ok := colors[item.ID()]
|
||||
color, ok := colors[info]
|
||||
if !ok {
|
||||
c = colorFor(info)
|
||||
colors[info] = c
|
||||
color = colorFor(info)
|
||||
colors[info] = color
|
||||
}
|
||||
ll[i] = item.Render(c, showTime)
|
||||
ll[i] = item.Render(color, showTime)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,14 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
}
|
||||
|
||||
func TestClusterMetaDelta(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
o, n model.ClusterMeta
|
||||
|
|
|
|||
|
|
@ -233,11 +233,11 @@ func (l *Log) Append(line *dao.LogItem) {
|
|||
}
|
||||
|
||||
// Notify fires of notifications to the listeners.
|
||||
func (l *Log) Notify(timedOut bool) {
|
||||
func (l *Log) Notify() {
|
||||
l.mx.Lock()
|
||||
defer l.mx.Unlock()
|
||||
|
||||
if timedOut && l.lastSent < len(l.lines) {
|
||||
if l.lastSent < len(l.lines) {
|
||||
l.fireLogBuffChanged(l.lines[l.lastSent:])
|
||||
l.lastSent = len(l.lines)
|
||||
}
|
||||
|
|
@ -253,7 +253,7 @@ func (l *Log) updateLogs(ctx context.Context, c dao.LogChan) {
|
|||
if !ok {
|
||||
log.Debug().Msgf("Closed channel detected. Bailing out...")
|
||||
l.Append(item)
|
||||
l.Notify(true)
|
||||
l.Notify()
|
||||
return
|
||||
}
|
||||
l.Append(item)
|
||||
|
|
@ -264,10 +264,10 @@ func (l *Log) updateLogs(ctx context.Context, c dao.LogChan) {
|
|||
}
|
||||
l.mx.RUnlock()
|
||||
if overflow {
|
||||
l.Notify(true)
|
||||
l.Notify()
|
||||
}
|
||||
case <-time.After(l.flushTimeout):
|
||||
l.Notify(true)
|
||||
l.Notify()
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
|
@ -322,11 +322,15 @@ func applyFilter(q string, lines dao.LogItems) (dao.LogItems, error) {
|
|||
}
|
||||
|
||||
func (l *Log) fireLogBuffChanged(lines dao.LogItems) {
|
||||
filtered, err := applyFilter(l.filter, lines)
|
||||
filtered := lines
|
||||
if l.filter != "" {
|
||||
var err error
|
||||
filtered, err = applyFilter(l.filter, lines)
|
||||
if err != nil {
|
||||
l.fireLogError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(filtered) > 0 {
|
||||
l.fireLogChanged(filtered)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUpdateLogs(t *testing.T) {
|
||||
size := 100
|
||||
m := NewLog(client.NewGVR("fred"), makeLogOpts(size), 10*time.Millisecond)
|
||||
m.Init(makeFactory())
|
||||
|
||||
v := newMockLogView()
|
||||
m.AddListener(v)
|
||||
|
||||
c := make(dao.LogChan)
|
||||
go func() {
|
||||
m.updateLogs(context.Background(), c)
|
||||
}()
|
||||
|
||||
for i := 0; i < 2*size; i++ {
|
||||
c <- dao.NewLogItemFromString("line" + strconv.Itoa(i))
|
||||
}
|
||||
close(c)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
assert.Equal(t, size, v.count)
|
||||
}
|
||||
|
||||
func BenchmarkUpdateLogs(b *testing.B) {
|
||||
size := 100
|
||||
m := NewLog(client.NewGVR("fred"), makeLogOpts(size), 10*time.Millisecond)
|
||||
m.Init(makeFactory())
|
||||
|
||||
v := newMockLogView()
|
||||
m.AddListener(v)
|
||||
|
||||
c := make(dao.LogChan)
|
||||
go func() {
|
||||
m.updateLogs(context.Background(), c)
|
||||
}()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
c <- dao.NewLogItemFromString("line" + strconv.Itoa(n))
|
||||
}
|
||||
close(c)
|
||||
}
|
||||
|
||||
// Helpers...
|
||||
|
||||
func makeLogOpts(count int) dao.LogOptions {
|
||||
return dao.LogOptions{
|
||||
Path: "fred",
|
||||
Container: "blee",
|
||||
Lines: int64(count),
|
||||
}
|
||||
}
|
||||
|
||||
type mockLogView struct {
|
||||
count int
|
||||
}
|
||||
|
||||
func newMockLogView() *mockLogView {
|
||||
return &mockLogView{}
|
||||
}
|
||||
|
||||
func (t *mockLogView) LogChanged(d dao.LogItems) {
|
||||
t.count += len(d.Lines())
|
||||
}
|
||||
func (t *mockLogView) LogCleared() {}
|
||||
func (t *mockLogView) LogFailed(err error) {}
|
||||
|
|
@ -29,7 +29,7 @@ func TestLogFullBuffer(t *testing.T) {
|
|||
data = append(data, dao.NewLogItemFromString("line"+strconv.Itoa(i)))
|
||||
m.Append(data[i])
|
||||
}
|
||||
m.Notify(true)
|
||||
m.Notify()
|
||||
|
||||
assert.Equal(t, 1, v.dataCalled)
|
||||
assert.Equal(t, 1, v.clearCalled)
|
||||
|
|
@ -73,7 +73,7 @@ func TestLogFilter(t *testing.T) {
|
|||
m.Append(data[i])
|
||||
}
|
||||
|
||||
m.Notify(true)
|
||||
m.Notify()
|
||||
assert.Equal(t, 1, v.dataCalled)
|
||||
assert.Equal(t, 1, v.clearCalled)
|
||||
assert.Equal(t, 0, v.errCalled)
|
||||
|
|
@ -100,7 +100,7 @@ func TestLogStartStop(t *testing.T) {
|
|||
for _, d := range data {
|
||||
m.Append(d)
|
||||
}
|
||||
m.Notify(true)
|
||||
m.Notify()
|
||||
m.Stop()
|
||||
|
||||
assert.Equal(t, 1, v.dataCalled)
|
||||
|
|
@ -122,7 +122,7 @@ func TestLogClear(t *testing.T) {
|
|||
for _, d := range data {
|
||||
m.Append(d)
|
||||
}
|
||||
m.Notify(true)
|
||||
m.Notify()
|
||||
m.Clear()
|
||||
|
||||
assert.Equal(t, 1, v.dataCalled)
|
||||
|
|
@ -167,7 +167,7 @@ func TestLogAppend(t *testing.T) {
|
|||
assert.Equal(t, 1, v.dataCalled)
|
||||
assert.Equal(t, items, v.data)
|
||||
|
||||
m.Notify(true)
|
||||
m.Notify()
|
||||
assert.Equal(t, 2, v.dataCalled)
|
||||
assert.Equal(t, 1, v.clearCalled)
|
||||
assert.Equal(t, 0, v.errCalled)
|
||||
|
|
@ -191,7 +191,7 @@ func TestLogTimedout(t *testing.T) {
|
|||
for _, d := range data {
|
||||
m.Append(d)
|
||||
}
|
||||
m.Notify(true)
|
||||
m.Notify()
|
||||
assert.Equal(t, 1, v.dataCalled)
|
||||
assert.Equal(t, 1, v.clearCalled)
|
||||
assert.Equal(t, 0, v.errCalled)
|
||||
|
|
|
|||
|
|
@ -235,16 +235,16 @@ func (l *Log) Logs() *Details {
|
|||
return l.logs
|
||||
}
|
||||
|
||||
var EOL = []byte("\n")
|
||||
|
||||
// Flush write logs to viewer.
|
||||
func (l *Log) Flush(lines dao.LogItems) {
|
||||
defer func(t time.Time) {
|
||||
log.Debug().Msgf("FLUSH %d--%v", len(lines), time.Since(t))
|
||||
}(time.Now())
|
||||
|
||||
showTime := l.Indicator().showTime
|
||||
ll := make([][]byte, len(lines))
|
||||
lines.Render(showTime, ll)
|
||||
fmt.Fprintln(l.ansiWriter, string(bytes.Join(ll, []byte("\n"))))
|
||||
if _, err := l.ansiWriter.Write(bytes.Join(ll, EOL)); err != nil {
|
||||
log.Error().Err(err).Msgf("write log failed")
|
||||
}
|
||||
l.logs.ScrollToEnd()
|
||||
l.indicator.Refresh()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ func TestLogAutoScroll(t *testing.T) {
|
|||
v := NewLog(client.NewGVR("v1/pods"), "fred/p1", "blee", false)
|
||||
v.Init(makeContext())
|
||||
v.GetModel().Set(dao.LogItems{dao.NewLogItemFromString("blee"), dao.NewLogItemFromString("bozo")})
|
||||
v.GetModel().Notify(true)
|
||||
v.GetModel().Notify()
|
||||
|
||||
assert.Equal(t, 14, len(v.Hints()))
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ func TestLogTimestamp(t *testing.T) {
|
|||
l.Logs().Clear()
|
||||
l.Flush(buff)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("%-30s %s", "ttt", "fred/blee:c1 Testing 1, 2, 3\n"), l.Logs().GetText(true))
|
||||
assert.Equal(t, fmt.Sprintf("%-30s %s", "ttt", "fred/blee:c1 Testing 1, 2, 3"), l.Logs().GetText(true))
|
||||
assert.Equal(t, 2, list.change)
|
||||
assert.Equal(t, 2, list.clear)
|
||||
assert.Equal(t, 0, list.fail)
|
||||
|
|
|
|||
Loading…
Reference in New Issue