Skip to content

Commit

Permalink
feat: 添加 Marshaler
Browse files Browse the repository at this point in the history
  • Loading branch information
caixw committed Nov 10, 2023
1 parent 9ed8c4b commit 6862586
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 52 deletions.
7 changes: 0 additions & 7 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package logs

import (
"encoding"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -174,12 +173,6 @@ func (h *textHandler) buildAttrs(b *Buffer, attrs []Attr) {
b.AppendFloat(float64(v), 'f', -1, 32)
case float64:
b.AppendFloat(v, 'f', -1, 64)
case encoding.TextMarshaler:
if bs, err := v.MarshalText(); err != nil {
b.AppendString("Err(").AppendString(err.Error()).AppendBytes(')')
} else {
b.AppendBytes(bs...)
}
default:
b.Append(p.V)
}
Expand Down
49 changes: 12 additions & 37 deletions handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,21 @@ import (
"time"

"github.com/issue9/assert/v3"
"github.com/issue9/term/v3/colors"
)

type (
marshalObject string
marshalErrObject string
)

func (o marshalObject) MarshalText() ([]byte, error) {
return []byte(o), nil
}
var _ Marshaler = marshalObject("")

func (o marshalObject) MarshalLog() string { return string(o) }

func (o marshalObject) MarshalJSON() ([]byte, error) {
return json.Marshal(string(o))
}

func (o marshalErrObject) MarshalText() ([]byte, error) {
return nil, errors.New("marshal text error")
}

func (o marshalErrObject) MarshalJSON() ([]byte, error) {
return nil, errors.New("marshal json error")
}
Expand Down Expand Up @@ -59,13 +54,13 @@ func TestTextHandler(t *testing.T) {
l := New(nil, WithCreated(layout), WithLocation(true))
e := newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))

buf := new(bytes.Buffer)
l = New(NewTextHandler(buf), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))
e.Output(l.WARN())
a.Equal(buf.String(), "[WARN] "+now.Format(layout)+" path.go:20\tmsg k1=v1 k2=v2 m1=m1\n")

Expand All @@ -75,22 +70,12 @@ func TestTextHandler(t *testing.T) {
l = New(NewTextHandler(b1, b2, b3), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))
e.Output(l.WARN())
a.Equal(b1.String(), "[WARN] "+now.Format(layout)+" path.go:20\tmsg k1=v1 k2=v2 m1=m1\n")
a.Equal(b2.String(), "[WARN] "+now.Format(layout)+" path.go:20\tmsg k1=v1 k2=v2 m1=m1\n")
a.Equal(b3.String(), "[WARN] "+now.Format(layout)+" path.go:20\tmsg k1=v1 k2=v2 m1=m1\n")

// error

buf.Reset()
l = New(NewTextHandler(buf), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1")).with(l, "m2", marshalErrObject("m2"))
e.Output(l.WARN())
a.Equal(buf.String(), "[WARN] "+now.Format(layout)+" path.go:20\tmsg k1=v1 k2=v2 m1=m1 m2=Err(marshal text error)\n")

// Handler.New

buf.Reset()
Expand All @@ -116,15 +101,15 @@ func TestJSONFormat(t *testing.T) {
l := New(nil, WithCreated(layout), WithLocation(true))
e := newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))

a.Panic(func() { NewJSONHandler() })

buf := new(bytes.Buffer)
l = New(NewJSONHandler(buf), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))
e.Output(l.WARN())
a.Equal(buf.String(), `{"level":"WARN","message":"msg","created":"`+now.Format(layout)+`","path":"path.go:20","attrs":[{"k1":"v1"},{"k2":"v2"},{"m1":"m1"}]}`)

Expand All @@ -133,7 +118,7 @@ func TestJSONFormat(t *testing.T) {
l = New(NewJSONHandler(b1, b2), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))
e.Output(l.WARN())
a.Equal(b1.String(), `{"level":"WARN","message":"msg","created":"`+now.Format(layout)+`","path":"path.go:20","attrs":[{"k1":"v1"},{"k2":"v2"},{"m1":"m1"}]}`).
Equal(b1.String(), b2.String())
Expand All @@ -144,7 +129,7 @@ func TestJSONFormat(t *testing.T) {
l = New(NewJSONHandler(buf), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1")).with(l, "m2", marshalErrObject("m2"))
e.with("m1", marshalObject("m1")).with("m2", marshalErrObject("m2"))
e.Output(l.WARN())
a.Equal(buf.String(), `{"level":"WARN","message":"msg","created":"`+now.Format(layout)+`","path":"path.go:20","attrs":[{"k1":"v1"},{"k2":"v2"},{"m1":"m1"},{"m2":"Err(json: error calling MarshalJSON for type logs.marshalErrObject: marshal json error)"}]}`)

Expand Down Expand Up @@ -176,26 +161,16 @@ func TestTermHandler(t *testing.T) {
l := New(nil, WithCreated(layout), WithLocation(true))
e := newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))

buf := new(bytes.Buffer)
l = New(NewTermHandler(buf, nil), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1"))
e.with("m1", marshalObject("m1"))
e.Output(l.WARN())
a.Equal(buf.String(), "[\033[33;49mWARN\033[0m] "+now.Format(layout)+" path.go:20\tmsg k1=v1 k2=v2 m1=m1\n")

// error

buf.Reset()
l = New(NewTermHandler(buf, map[Level]colors.Color{LevelWarn: colors.Red}), WithCreated(layout), WithLocation(true))
e = newRecord(a, l)
e.AppendCreated = func(b *Buffer) { b.AppendTime(now, l.createdFormat) }
e.with(l, "m1", marshalObject("m1")).with(l, "m2", marshalErrObject("m2"))
e.Output(l.WARN())
a.Equal(buf.String(), "[\033[31;49mWARN\033[0m] "+now.Format(layout)+" path.go:20\tmsg k1=v1 k2=v2 m1=m1 m2=Err(marshal text error)\n")

// Handler.New

buf.Reset()
Expand Down
2 changes: 1 addition & 1 deletion logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (l *Logger) With(name string, val any) Recorder {

r := withRecordPool.Get().(*withRecorder)
r.l = l
r.r = l.logs.NewRecord().with(l.logs, name, val)
r.r = l.logs.NewRecord().with(name, val)
return r
}

Expand Down
4 changes: 4 additions & 0 deletions logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type Logs struct {
printer *localeutil.Printer
}

type Marshaler interface {
MarshalLog() string
}

func map2Slice(p *localeutil.Printer, attrs map[string]any) []Attr {
pairs := make([]Attr, 0, len(attrs))

Expand Down
35 changes: 30 additions & 5 deletions record.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type (
//
// 返回对象与当前对象未必是同一个,由实现者决定。
// 且返回对象是一次性的,在调用 Error、String 等输出之后即被回收。
//
// 如果 val 实现了 [localeutil.Stringer] 或是 [Marshaler] 接口,
// 将被转换成字符串保存。
With(name string, val any) Recorder

// Error 将一条错误信息作为一条日志输出
Expand All @@ -32,17 +35,31 @@ type (
// 采用此方法会比 Print(err) 有更好的性能。
//
// 如果 err 实现了 [xerrors.FormatError] 接口,同时也会打印调用信息。
//
// NOTE: 此操作之后,当前对象不再可用!
Error(err error)

// String 将字符串作为一条日志输出
//
// 这是 Print 的特化版本,在已知类型为字符串时,
// 采用此方法会比 Print(s) 有更好的性能。
//
// NOTE: 此操作之后,当前对象不再可用!
String(s string)

// 输出一条日志信息
//
// NOTE: 此操作之后,当前对象不再可用!
Print(v ...any)

// 输出一条日志信息
//
// NOTE: 此操作之后,当前对象不再可用!
Println(v ...any)

// 输出一条日志信息
//
// NOTE: 此操作之后,当前对象不再可用!
Printf(format string, v ...any)
}

Expand Down Expand Up @@ -115,11 +132,19 @@ func (e *Record) initLocationCreated(depth int) *Record {
return e
}

func (e *Record) with(logs *Logs, name string, val any) *Record {
if ls, ok := val.(localeutil.Stringer); ok && logs.printer != nil {
val = ls.LocaleString(logs.printer)
func (e *Record) with(name string, val any) *Record {
switch v := val.(type) {
case localeutil.Stringer:
if e.logs.printer != nil {
e.Attrs = append(e.Attrs, Attr{K: name, V: v.LocaleString(e.logs.printer)})
} else {
e.Attrs = append(e.Attrs, Attr{K: name, V: v})
}
case Marshaler:
e.Attrs = append(e.Attrs, Attr{K: name, V: v.MarshalLog()})
default:
e.Attrs = append(e.Attrs, Attr{K: name, V: v})
}
e.Attrs = append(e.Attrs, Attr{K: name, V: val})
return e
}

Expand Down Expand Up @@ -234,7 +259,7 @@ func replaceLocaleString(p *localeutil.Printer, v []any) {
}

func (e *withRecorder) With(name string, val any) Recorder {
e.r.with(e.l.logs, name, val)
e.r.with(name, val)
return e
}

Expand Down
4 changes: 2 additions & 2 deletions slog.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ func (h *logsHandler) Handle(ctx context.Context, r slog.Record) error {
rr.AppendMessage = func(b *Buffer) { b.AppendString(r.Message) }

for _, attr := range h.attrs {
rr.with(h.l, h.prefix+attr.Key, attr.Value)
rr.with(h.prefix+attr.Key, attr.Value)
}
r.Attrs(func(attr slog.Attr) bool {
rr.with(h.l, h.prefix+attr.Key, attr.Value)
rr.with(h.prefix+attr.Key, attr.Value)
return true
})

Expand Down

0 comments on commit 6862586

Please sign in to comment.