Skip to content

Commit

Permalink
chore: prepare for slog attribute support
Browse files Browse the repository at this point in the history
  • Loading branch information
op authored and aymanbagabas committed May 7, 2024
1 parent dd7bc94 commit 45799c6
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 76 deletions.
114 changes: 61 additions & 53 deletions json.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,88 +8,96 @@ import (
)

func (l *Logger) jsonFormatter(keyvals ...interface{}) {
jw := jsonWriter{w: &l.b}
jw := &jsonWriter{w: &l.b}
jw.start()

for i := 0; i < len(keyvals); i += 2 {
switch keyvals[i] {
case TimestampKey:
if t, ok := keyvals[i+1].(time.Time); ok {
jw.write(TimestampKey, t.Format(l.timeFormat))
}
case LevelKey:
if level, ok := keyvals[i+1].(Level); ok {
jw.write(LevelKey, level.String())
}
case CallerKey:
if caller, ok := keyvals[i+1].(string); ok {
jw.write(CallerKey, caller)
}
case PrefixKey:
if prefix, ok := keyvals[i+1].(string); ok {
jw.write(PrefixKey, prefix)
}
case MessageKey:
if msg := keyvals[i+1]; msg != nil {
jw.write(MessageKey, fmt.Sprint(msg))
}
l.jsonFormatterKeyVal(jw, keyvals[i], keyvals[i+1])
}

jw.end()
l.b.WriteRune('\n')
}

func (l *Logger) jsonFormatterKeyVal(jw *jsonWriter, anyKey, value any) {
switch anyKey {
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:
switch k := anyKey.(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 fmt.Stringer:
jw.objectValue(v.String())
default:
var (
key string
val interface{}
)
switch k := keyvals[i].(type) {
case fmt.Stringer:
key = k.String()
case error:
key = k.Error()
default:
key = fmt.Sprint(k)
}
switch v := keyvals[i+1].(type) {
case error:
val = v.Error()
case fmt.Stringer:
val = v.String()
default:
val = v
}
jw.write(key, val)
jw.objectValue(v)
}
}
jw.end()
}

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('}')
w.w.WriteRune('\n')
}

func (w *jsonWriter) write(key string, value any) {
// store pos if we need to rewind
pos := w.w.Len()
func (w *jsonWriter) objectItem(key string, value any) {
w.objectKey(key)
w.objectValue(value)
}

// add separator when buffer is longer than '{'
if w.w.Len() > 1 {
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)
return
w.w.WriteString(`"invalid key"`)
}
w.w.WriteRune(':')
}

pos = w.w.Len()
err = w.writeEncoded(value)
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"`)
Expand Down
46 changes: 23 additions & 23 deletions json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,101 +209,101 @@ func TestJsonWriter(t *testing.T) {
"string",
func(w *jsonWriter) {
w.start()
w.write("a", "value")
w.objectItem("a", "value")
w.end()
},
`{"a":"value"}` + "\n",
`{"a":"value"}`,
},
{
"int",
func(w *jsonWriter) {
w.start()
w.write("a", 123)
w.objectItem("a", 123)
w.end()
},
`{"a":123}` + "\n",
`{"a":123}`,
},
{
"bytes",
func(w *jsonWriter) {
w.start()
w.write("b", []byte{0x0, 0x1})
w.objectItem("b", []byte{0x0, 0x1})
w.end()
},
`{"b":"AAE="}` + "\n",
`{"b":"AAE="}`,
},
{
"no fields",
func(w *jsonWriter) {
w.start()
w.end()
},
`{}` + "\n",
`{}`,
},
{
"multiple in asc order",
func(w *jsonWriter) {
w.start()
w.write("a", "value")
w.write("b", "some-other")
w.objectItem("a", "value")
w.objectItem("b", "some-other")
w.end()
},
`{"a":"value","b":"some-other"}` + "\n",
`{"a":"value","b":"some-other"}`,
},
{
"multiple in desc order",
func(w *jsonWriter) {
w.start()
w.write("b", "some-other")
w.write("a", "value")
w.objectItem("b", "some-other")
w.objectItem("a", "value")
w.end()
},
`{"b":"some-other","a":"value"}` + "\n",
`{"b":"some-other","a":"value"}`,
},
{
"depth",
func(w *jsonWriter) {
w.start()
w.write("a", map[string]int{"b": 123})
w.objectItem("a", map[string]int{"b": 123})
w.end()
},
`{"a":{"b":123}}` + "\n",
`{"a":{"b":123}}`,
},
{
"key contains reserved",
func(w *jsonWriter) {
w.start()
w.write("a:\"b", "value")
w.objectItem("a:\"b", "value")
w.end()
},
`{"a:\"b":"value"}` + "\n",
`{"a:\"b":"value"}`,
},
{
"pointer",
func(w *jsonWriter) {
w.start()
w.write("a", ptr("pointer"))
w.objectItem("a", ptr("pointer"))
w.end()
},
`{"a":"pointer"}` + "\n",
`{"a":"pointer"}`,
},
{
"double-pointer",
func(w *jsonWriter) {
w.start()
w.write("a", ptr(ptr("pointer")))
w.objectItem("a", ptr(ptr("pointer")))
w.end()
},
`{"a":"pointer"}` + "\n",
`{"a":"pointer"}`,
},
{
"invalid",
func(w *jsonWriter) {
w.start()
w.write("a", invalidJSON{})
w.objectItem("a", invalidJSON{})
w.end()
},
`{"a":"invalid value"}` + "\n",
`{"a":"invalid value"}`,
},
}

Expand Down

0 comments on commit 45799c6

Please sign in to comment.