0
0
forked from toolshed/abra
decentral1se 1723025fbf
build: go 1.24
We were running behind and there were quite some deprecations to update.
This was mostly in the upstream copy/pasta package but seems quite
minimal.
2025-03-16 12:31:45 +01:00

152 lines
2.8 KiB
Go

package log
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
func (l *Logger) jsonFormatter(keyvals ...interface{}) {
jw := &jsonWriter{w: &l.b}
jw.start()
i := 0
for i < len(keyvals) {
switch kv := keyvals[i].(type) {
case slogAttr:
l.jsonFormatterRoot(jw, kv.Key, kv.Value)
i++
default:
if i+1 < len(keyvals) {
l.jsonFormatterRoot(jw, keyvals[i], keyvals[i+1])
}
i += 2
}
}
jw.end()
l.b.WriteRune('\n')
}
func (l *Logger) jsonFormatterRoot(jw *jsonWriter, key, value any) {
switch key {
case TimestampKey:
if t, ok := value.(time.Time); ok {
jw.objectItem(TimestampKey, t.Format(l.timeFormat))
}
case LevelKey:
if level, ok := value.(Level); ok {
jw.objectItem(LevelKey, level.String())
}
case CallerKey:
if caller, ok := value.(string); ok {
jw.objectItem(CallerKey, caller)
}
case PrefixKey:
if prefix, ok := value.(string); ok {
jw.objectItem(PrefixKey, prefix)
}
case MessageKey:
if msg := value; msg != nil {
jw.objectItem(MessageKey, fmt.Sprint(msg))
}
default:
l.jsonFormatterItem(jw, key, value)
}
}
func (l *Logger) jsonFormatterItem(jw *jsonWriter, key, value any) {
switch k := key.(type) {
case fmt.Stringer:
jw.objectKey(k.String())
case error:
jw.objectKey(k.Error())
default:
jw.objectKey(fmt.Sprint(k))
}
switch v := value.(type) {
case error:
jw.objectValue(v.Error())
case slogLogValuer:
l.writeSlogValue(jw, v.LogValue())
case slogValue:
l.writeSlogValue(jw, v.Resolve())
case fmt.Stringer:
jw.objectValue(v.String())
default:
jw.objectValue(v)
}
}
func (l *Logger) writeSlogValue(jw *jsonWriter, v slogValue) {
switch v.Kind() { //nolint:exhaustive
case slogKindGroup:
jw.start()
for _, attr := range v.Group() {
l.jsonFormatterItem(jw, attr.Key, attr.Value)
}
jw.end()
default:
jw.objectValue(v.Any())
}
}
type jsonWriter struct {
w *bytes.Buffer
d int
}
func (w *jsonWriter) start() {
w.w.WriteRune('{')
w.d = 0
}
func (w *jsonWriter) end() {
w.w.WriteRune('}')
}
func (w *jsonWriter) objectItem(key string, value any) {
w.objectKey(key)
w.objectValue(value)
}
func (w *jsonWriter) objectKey(key string) {
if w.d > 0 {
w.w.WriteRune(',')
}
w.d++
pos := w.w.Len()
err := w.writeEncoded(key)
if err != nil {
w.w.Truncate(pos)
w.w.WriteString(`"invalid key"`)
}
w.w.WriteRune(':')
}
func (w *jsonWriter) objectValue(value any) {
pos := w.w.Len()
err := w.writeEncoded(value)
if err != nil {
w.w.Truncate(pos)
w.w.WriteString(`"invalid value"`)
}
}
func (w *jsonWriter) writeEncoded(v any) error {
e := json.NewEncoder(w.w)
e.SetEscapeHTML(false)
if err := e.Encode(v); err != nil {
return fmt.Errorf("failed to encode value: %w", err)
}
// trailing \n added by json.Encode
b := w.w.Bytes()
if len(b) > 0 && b[len(b)-1] == '\n' {
w.w.Truncate(w.w.Len() - 1)
}
return nil
}