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
@@ -2,6 +2,7 @@ package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -24,3 +25,41 @@ type TransportEvent struct {
|
||||
// Structured entry for re-serializing sinks (chain links). Zero Time => absent
|
||||
Entry LogEntry
|
||||
}
|
||||
|
||||
// Levels are the entry levels by rising severity, each with the words naming
|
||||
// it in a line: the sources, the console sink's painter and the viewer share them
|
||||
var Levels = []struct {
|
||||
Level string `json:"level"`
|
||||
Names []string `json:"names"`
|
||||
}{
|
||||
{"TRACE", []string{"TRACE"}},
|
||||
{"DEBUG", []string{"DEBUG", "DBG"}},
|
||||
{"INFO", []string{"INFO", "INF"}},
|
||||
{"WARN", []string{"WARN", "WARNING"}},
|
||||
{"ERROR", []string{"ERROR", "ERR", "FATAL"}},
|
||||
}
|
||||
|
||||
// LevelWord finds the first whole word of text, in any case, that names a
|
||||
// level, or names want when it is set; it returns the level and the word's
|
||||
// bounds, and "" when no word does.
|
||||
func LevelWord[T string | []byte](text T, want string) (level string, start, end int) {
|
||||
for i := 0; i < len(text); i = end {
|
||||
for i < len(text) && !wordByte(text[i]) {
|
||||
i++
|
||||
}
|
||||
for end = i; end < len(text) && wordByte(text[end]); end++ {
|
||||
}
|
||||
for _, l := range Levels {
|
||||
for _, name := range l.Names {
|
||||
if end-i == len(name) && (want == "" || want == l.Level) && strings.EqualFold(string(text[i:end]), name) {
|
||||
return l.Level, i, end
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", 0, 0
|
||||
}
|
||||
|
||||
func wordByte(c byte) bool {
|
||||
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_'
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package core
|
||||
|
||||
import "testing"
|
||||
|
||||
// A line's level is its first whole word, in any case, naming a level, not the
|
||||
// most severe one named; a wanted level skips the names of the others.
|
||||
func TestLevelIsTheFirstWordNamingOne(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
text, want, level string
|
||||
start, end int
|
||||
}{
|
||||
{"warning disk full", "", "WARN", 0, 7},
|
||||
{"DBG x", "", "DEBUG", 0, 3},
|
||||
{"2026-10-05 [Info] retry after error", "", "INFO", 12, 16},
|
||||
{`{"level":"fatal","msg":"x"}`, "", "ERROR", 10, 15},
|
||||
{"terror informal x_ERR", "", "", 0, 0},
|
||||
{"INFO then ERR", "ERROR", "ERROR", 10, 13},
|
||||
} {
|
||||
level, start, end := LevelWord(c.text, c.want)
|
||||
if level != c.level || start != c.start || end != c.end {
|
||||
t.Errorf("%q want %q: got %q [%d:%d], want %q [%d:%d]", c.text, c.want, level, start, end, c.level, c.start, c.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user