v0.26.3 web viewer improvement
This commit is contained in:
1 parent
d745a128a2
commit
c00c076d9b
14 files changed
+159
-85
No files matched your search
@@ -69,18 +69,14 @@ const (
|
||||
DefaultConsoleColor = "auto"
|
||||
)
|
||||
|
||||
// levelColors paints the first of a level's names in an entry, ANSI 16 so
|
||||
// the terminal's theme picks the shades and a text console renders them.
|
||||
// Names run longest first; cyan, not blue, stays readable on black.
|
||||
var levelColors = map[string]struct {
|
||||
names []string
|
||||
style inline.Style
|
||||
}{
|
||||
"ERROR": {[]string{"ERROR", "FATAL", "ERR"}, inline.FgANSI(color.ANSIRed).Bold()},
|
||||
"WARN": {[]string{"WARNING", "WARN"}, inline.FgANSI(color.ANSIYellow)},
|
||||
"INFO": {[]string{"INFO", "INF"}, inline.FgANSI(color.ANSIGreen)},
|
||||
"DEBUG": {[]string{"DEBUG", "DBG"}, inline.FgANSI(color.ANSICyan)},
|
||||
"TRACE": {[]string{"TRACE"}, inline.FgANSI(color.ANSIBrightBlack)},
|
||||
// levelStyles colors the levels in ANSI 16, so the terminal's theme picks the
|
||||
// shades and a text console renders them; cyan, not blue, stays readable on black
|
||||
var levelStyles = map[string]inline.Style{
|
||||
"ERROR": inline.FgANSI(color.ANSIRed).Bold(),
|
||||
"WARN": inline.FgANSI(color.ANSIYellow),
|
||||
"INFO": inline.FgANSI(color.ANSIGreen),
|
||||
"DEBUG": inline.FgANSI(color.ANSICyan),
|
||||
"TRACE": inline.FgANSI(color.ANSIBrightBlack),
|
||||
}
|
||||
|
||||
// NewConsoleSinkPlugin creates a console sink through plugin factory
|
||||
@@ -273,42 +269,23 @@ func (cs *ConsoleSink) write(event core.TransportEvent) {
|
||||
cs.lastProcessed.Store(time.Now())
|
||||
}
|
||||
|
||||
// paintLevel colors the first whole-word, case-insensitive occurrence of a
|
||||
// name of level, after escaping: the escape sequences are the sink's own.
|
||||
// paintLevel colors the first word naming the entry's level, after escaping:
|
||||
// the escape sequences are the sink's own
|
||||
func paintLevel(p *inline.Printer, payload []byte, level string) []byte {
|
||||
lc, ok := levelColors[level]
|
||||
level, _, _ = core.LevelWord(level, "")
|
||||
style, ok := levelStyles[level]
|
||||
if !ok {
|
||||
return payload
|
||||
}
|
||||
for _, name := range lc.names {
|
||||
for i := 0; i+len(name) <= len(payload); i++ {
|
||||
j := i + len(name)
|
||||
if !nameAt(payload[i:j], name) || i > 0 && word(payload[i-1]) || j < len(payload) && word(payload[j]) {
|
||||
continue
|
||||
}
|
||||
out := make([]byte, 0, len(payload)+16)
|
||||
out = append(out, payload[:i]...)
|
||||
out = append(out, p.Paint(string(payload[i:j]), lc.style)...)
|
||||
return append(out, payload[j:]...)
|
||||
}
|
||||
if _, i, j := core.LevelWord(payload, level); i < j {
|
||||
out := make([]byte, 0, len(payload)+16)
|
||||
out = append(out, payload[:i]...)
|
||||
out = append(out, p.Paint(string(payload[i:j]), style)...)
|
||||
return append(out, payload[j:]...)
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
// nameAt compares ASCII letters without case; name is upper case
|
||||
func nameAt(b []byte, name string) bool {
|
||||
for k := range len(name) {
|
||||
if c := b[k]; c != name[k] && c != name[k]+'a'-'A' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func word(c byte) bool {
|
||||
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_'
|
||||
}
|
||||
|
||||
// escapeControls writes what a terminal would act on or reorder (C0 and C1
|
||||
// controls but tab, DEL, bidi controls, line separators, invalid UTF-8) as
|
||||
// <hex>, keeping the final newline: a log line cannot drive the terminal.
|
||||
|
||||
@@ -29,8 +29,8 @@ func TestEscapeControlsKeepsOnlyLayout(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The entry's level is painted where its line first names it as a whole
|
||||
// word, in any case, longest name first; other words and levels stay plain.
|
||||
// The entry's level, under any of its names, is painted where its line first
|
||||
// names it as a whole word, in any case; other words and levels stay plain.
|
||||
func TestPaintLevelColorsTheFirstWholeName(t *testing.T) {
|
||||
p := inline.New(io.Discard)
|
||||
p.SetColor(true)
|
||||
@@ -38,6 +38,7 @@ func TestPaintLevelColorsTheFirstWholeName(t *testing.T) {
|
||||
for _, c := range []struct{ in, level, want string }{
|
||||
{"2026 ERROR boom ERROR\n", "ERROR", "2026 " + red + "ERROR\x1b[0m boom ERROR\n"},
|
||||
{"[warning] disk\n", "WARN", "[" + yellow + "warning\x1b[0m] disk\n"},
|
||||
{"INFO: WARN disk\n", "warning", "INFO: " + yellow + "WARN\x1b[0m disk\n"},
|
||||
{"terror_x ERR:1\n", "ERROR", "terror_x " + red + "ERR\x1b[0m:1\n"},
|
||||
{"INFOS informal\n", "INFO", "INFOS informal\n"},
|
||||
{"ERROR without level\n", "", "ERROR without level\n"},
|
||||
|
||||
Reference in new issue
Block a user