log: save some cpu by simplifying coloring, avoid many cases of escaping

This commit is contained in:
Martin Holst Swende 2023-11-14 22:43:44 +01:00
parent 99f3e24709
commit d929f63b8f
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
2 changed files with 66 additions and 64 deletions

View file

@ -15,7 +15,6 @@ import (
const ( const (
timeFormat = "2006-01-02T15:04:05-0700" timeFormat = "2006-01-02T15:04:05-0700"
termTimeFormat = "01-02|15:04:05.000"
floatFormat = 'f' floatFormat = 'f'
termMsgJust = 40 termMsgJust = 40
termCtxMaxPadding = 40 termCtxMaxPadding = 40
@ -49,40 +48,43 @@ type TerminalStringer interface {
func (h *TerminalHandler) TerminalFormat(buf []byte, r slog.Record, usecolor bool) []byte { func (h *TerminalHandler) TerminalFormat(buf []byte, r slog.Record, usecolor bool) []byte {
msg := escapeMessage(r.Message) msg := escapeMessage(r.Message)
var color = 0 var color = ""
if usecolor { if usecolor {
switch r.Level { switch r.Level {
case LevelCrit: case LevelCrit:
color = 35 color = "\x1b[35m"
case slog.LevelError: case slog.LevelError:
color = 31 color = "\x1b[31m"
case slog.LevelWarn: case slog.LevelWarn:
color = 33 color = "\x1b[33m"
case slog.LevelInfo: case slog.LevelInfo:
color = 32 color = "\x1b[32m"
case slog.LevelDebug: case slog.LevelDebug:
color = 36 color = "\x1b[36m"
case LevelTrace: case LevelTrace:
color = 34 color = "\x1b[34m"
} }
} }
if buf == nil { if buf == nil {
buf = make([]byte, 0, 30+termMsgJust) buf = make([]byte, 0, 30+termMsgJust)
} }
b := bytes.NewBuffer(buf) b := bytes.NewBuffer(buf)
lvl := LevelAlignedString(r.Level)
if color > 0 { if color != "" { // Start color
// TODO improve this b.WriteString(color)
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s ", color, lvl, r.Time.Format(termTimeFormat), msg) b.WriteString(LevelAlignedString(r.Level))
b.WriteString("\x1b[0m")
} else { } else {
b.WriteString(lvl) b.WriteString(LevelAlignedString(r.Level))
}
b.WriteString("[") b.WriteString("[")
writeTimeTermFormat(b, r.Time) writeTimeTermFormat(b, r.Time)
b.WriteString("] ") b.WriteString("] ")
b.WriteString(msg) b.WriteString(msg)
}
// try to justify the log output for short messages // try to justify the log output for short messages
length := utf8.RuneCountInString(msg) //length := utf8.RuneCountInString(msg)
length := len(msg)
if (r.NumAttrs()+len(h.attrs)) > 0 && length < termMsgJust { if (r.NumAttrs()+len(h.attrs)) > 0 && length < termMsgJust {
b.Write(spaces[:termMsgJust-length]) b.Write(spaces[:termMsgJust-length])
} }
@ -92,17 +94,18 @@ func (h *TerminalHandler) TerminalFormat(buf []byte, r slog.Record, usecolor boo
return b.Bytes() return b.Bytes()
} }
func (h *TerminalHandler) logfmt(buf *bytes.Buffer, r slog.Record, color int) { func (h *TerminalHandler) logfmt(buf *bytes.Buffer, r slog.Record, color string) {
writeAttr := func(attr slog.Attr, first, last bool) { writeAttr := func(attr slog.Attr, first, last bool) {
//if !first { //if !first {
buf.WriteByte(' ') buf.WriteByte(' ')
//} //}
key := escapeString(attr.Key)
if color > 0 { if color != "" {
// TODO improve this buf.WriteString(color)
fmt.Fprintf(buf, "\x1b[%dm%s\x1b[0m=", color, key) buf.Write(appendEscapeString(buf.AvailableBuffer(), attr.Key))
buf.WriteString("\x1b[0m=")
} else { } else {
buf.WriteString(key) buf.Write(appendEscapeString(buf.AvailableBuffer(), attr.Key))
buf.WriteByte('=') buf.WriteByte('=')
} }
tmp := buf.AvailableBuffer() tmp := buf.AvailableBuffer()
@ -302,34 +305,32 @@ func appendU256(dst []byte, n *uint256.Int) []byte {
// escaping/quoting if needed. // escaping/quoting if needed.
func appendEscapeString(dst []byte, s string) []byte { func appendEscapeString(dst []byte, s string) []byte {
needsQuoting := false needsQuoting := false
needsEscaping := false
for _, r := range s { for _, r := range s {
// We quote everything below " (0x22) and above~ (0x7E), plus equal-sign // If it contains spaces or equal-sign, we need to quote it.
if r <= '"' || r > '~' || r == '=' { if r == ' ' || r == '=' {
needsQuoting = true needsQuoting = true
continue
}
// We need to escape it, if it contains
// - character " (0x22) and lower (except space)
// - characters above ~ (0x7E), plus equal-sign
if r <= '"' || r > '~' {
needsEscaping = true
break break
} }
} }
if !needsQuoting { if needsEscaping {
return append(dst, []byte(s)...)
}
return strconv.AppendQuote(dst, s) return strconv.AppendQuote(dst, s)
}
// escapeString checks if the provided string needs escaping/quoting, and
// calls strconv.Quote if needed
func escapeString(s string) string {
needsQuoting := false
for _, r := range s {
// We quote everything below " (0x22) and above~ (0x7E), plus equal-sign
if r <= '"' || r > '~' || r == '=' {
needsQuoting = true
break
} }
// No escaping needed, but we might have to place within quote-marks, in case
// it contained a space
if needsQuoting {
dst = append(dst, '"')
dst = append(dst, []byte(s)...)
return append(dst, '"')
} }
if !needsQuoting { return append(dst, []byte(s)...)
return s
}
return strconv.Quote(s)
} }
// escapeMessage checks if the provided string needs escaping/quoting, similarly // escapeMessage checks if the provided string needs escaping/quoting, similarly
@ -355,7 +356,7 @@ func escapeMessage(s string) string {
return strconv.Quote(s) return strconv.Quote(s)
} }
// writeTimeTermFormat // writeTimeTermFormat writes on the format "01-02|15:04:05.000"
func writeTimeTermFormat(buf *bytes.Buffer, t time.Time) { func writeTimeTermFormat(buf *bytes.Buffer, t time.Time) {
_, month, day := t.Date() _, month, day := t.Date()
writePosIntWidth(buf, int(month), 2) writePosIntWidth(buf, int(month), 2)

View file

@ -144,9 +144,10 @@ func TestLoggerOutput(t *testing.T) {
} }
const termTimeFormat = "01-02|15:04:05.000"
func BenchmarkAppendFormat(b *testing.B) { func BenchmarkAppendFormat(b *testing.B) {
var now = time.Now() var now = time.Now()
b.Run("fmt time.Format", func(b *testing.B) { b.Run("fmt time.Format", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
fmt.Fprintf(io.Discard, "%s", now.Format(termTimeFormat)) fmt.Fprintf(io.Discard, "%s", now.Format(termTimeFormat))
@ -158,22 +159,22 @@ func BenchmarkAppendFormat(b *testing.B) {
now.AppendFormat(nil, termTimeFormat) now.AppendFormat(nil, termTimeFormat)
} }
}) })
//var buf = new(bytes.Buffer) var buf = new(bytes.Buffer)
//b.Run("time.Custom", func(b *testing.B) { b.Run("time.Custom", func(b *testing.B) {
// for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
// writeTimeTermFormat(buf, now) writeTimeTermFormat(buf, now)
// buf.Reset() buf.Reset()
// } }
//}) })
} }
//func TestTimeFormat(t *testing.T) { func TestTermTimeFormat(t *testing.T) {
// var now = time.Now() var now = time.Now()
// want := now.AppendFormat(nil, termTimeFormat) want := now.AppendFormat(nil, termTimeFormat)
// var b = new(bytes.Buffer) var b = new(bytes.Buffer)
// writeTimeTermFormat(b, now) writeTimeTermFormat(b, now)
// have := b.Bytes() have := b.Bytes()
// if !bytes.Equal(have, want) { if !bytes.Equal(have, want) {
// t.Errorf("have != want\nhave: %q\nwant: %q\n", have, want) t.Errorf("have != want\nhave: %q\nwant: %q\n", have, want)
// } }
//} }