json.go

  1package log
  2
  3import (
  4	"bytes"
  5	"encoding/json"
  6	"fmt"
  7	"time"
  8)
  9
 10func (l *Logger) jsonFormatter(keyvals ...interface{}) {
 11	jw := &jsonWriter{w: &l.b}
 12	jw.start()
 13
 14	i := 0
 15	for i < len(keyvals) {
 16		switch kv := keyvals[i].(type) {
 17		case slogAttr:
 18			l.jsonFormatterRoot(jw, kv.Key, kv.Value)
 19			i++
 20		default:
 21			if i+1 < len(keyvals) {
 22				l.jsonFormatterRoot(jw, keyvals[i], keyvals[i+1])
 23			}
 24			i += 2
 25		}
 26	}
 27
 28	jw.end()
 29	l.b.WriteRune('\n')
 30}
 31
 32func (l *Logger) jsonFormatterRoot(jw *jsonWriter, key, value any) {
 33	switch key {
 34	case TimestampKey:
 35		if t, ok := value.(time.Time); ok {
 36			jw.objectItem(TimestampKey, t.Format(l.timeFormat))
 37		}
 38	case LevelKey:
 39		if level, ok := value.(Level); ok {
 40			jw.objectItem(LevelKey, level.String())
 41		}
 42	case CallerKey:
 43		if caller, ok := value.(string); ok {
 44			jw.objectItem(CallerKey, caller)
 45		}
 46	case PrefixKey:
 47		if prefix, ok := value.(string); ok {
 48			jw.objectItem(PrefixKey, prefix)
 49		}
 50	case MessageKey:
 51		if msg := value; msg != nil {
 52			jw.objectItem(MessageKey, fmt.Sprint(msg))
 53		}
 54	default:
 55		l.jsonFormatterItem(jw, key, value)
 56	}
 57}
 58
 59func (l *Logger) jsonFormatterItem(jw *jsonWriter, key, value any) {
 60	switch k := key.(type) {
 61	case fmt.Stringer:
 62		jw.objectKey(k.String())
 63	case error:
 64		jw.objectKey(k.Error())
 65	default:
 66		jw.objectKey(fmt.Sprint(k))
 67	}
 68	switch v := value.(type) {
 69	case error:
 70		jw.objectValue(v.Error())
 71	case slogLogValuer:
 72		l.writeSlogValue(jw, v.LogValue())
 73	case slogValue:
 74		l.writeSlogValue(jw, v.Resolve())
 75	case fmt.Stringer:
 76		jw.objectValue(v.String())
 77	default:
 78		jw.objectValue(v)
 79	}
 80}
 81
 82func (l *Logger) writeSlogValue(jw *jsonWriter, v slogValue) {
 83	switch v.Kind() {
 84	case slogKindGroup:
 85		jw.start()
 86		for _, attr := range v.Group() {
 87			l.jsonFormatterItem(jw, attr.Key, attr.Value)
 88		}
 89		jw.end()
 90	default:
 91		jw.objectValue(v.Any())
 92	}
 93}
 94
 95type jsonWriter struct {
 96	w *bytes.Buffer
 97	d int
 98}
 99
100func (w *jsonWriter) start() {
101	w.w.WriteRune('{')
102	w.d = 0
103}
104
105func (w *jsonWriter) end() {
106	w.w.WriteRune('}')
107}
108
109func (w *jsonWriter) objectItem(key string, value any) {
110	w.objectKey(key)
111	w.objectValue(value)
112}
113
114func (w *jsonWriter) objectKey(key string) {
115	if w.d > 0 {
116		w.w.WriteRune(',')
117	}
118	w.d++
119
120	pos := w.w.Len()
121	err := w.writeEncoded(key)
122	if err != nil {
123		w.w.Truncate(pos)
124		w.w.WriteString(`"invalid key"`)
125	}
126	w.w.WriteRune(':')
127}
128
129func (w *jsonWriter) objectValue(value any) {
130	pos := w.w.Len()
131	err := w.writeEncoded(value)
132	if err != nil {
133		w.w.Truncate(pos)
134		w.w.WriteString(`"invalid value"`)
135	}
136}
137
138func (w *jsonWriter) writeEncoded(v any) error {
139	e := json.NewEncoder(w.w)
140	e.SetEscapeHTML(false)
141	if err := e.Encode(v); err != nil {
142		return err
143	}
144
145	// trailing \n added by json.Encode
146	b := w.w.Bytes()
147	if len(b) > 0 && b[len(b)-1] == '\n' {
148		w.w.Truncate(w.w.Len() - 1)
149	}
150	return nil
151}