Skip to content

Commit

Permalink
Add call stack for json formatter.
Browse files Browse the repository at this point in the history
  • Loading branch information
edoger committed Mar 30, 2022
1 parent 9c0d4d8 commit cc3802b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 10 deletions.
38 changes: 30 additions & 8 deletions json_formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func DefaultJSONFormatter() Formatter {
func NewJSONFormatter(keys map[string]string, full bool) (Formatter, error) {
m := map[string]string{
"name": "name", "time": "time", "level": "level", "message": "message",
"fields": "fields", "caller": "caller",
"fields": "fields", "caller": "caller", "stack": "stack",
}

structure := true
Expand All @@ -56,7 +56,7 @@ func NewJSONFormatter(keys map[string]string, full bool) (Formatter, error) {
}
f := &jsonFormatter{
name: m["name"], time: m["time"], level: m["level"], message: m["message"],
fields: m["fields"], caller: m["caller"],
fields: m["fields"], caller: m["caller"], stack: m["stack"],
full: full, structure: structure,
}
return f, nil
Expand All @@ -79,6 +79,7 @@ type jsonFormatter struct {
message string
fields string
caller string
stack string
full bool
structure bool
}
Expand All @@ -91,7 +92,8 @@ type jsonFormatterObject struct {
Level string `json:"level"`
Message string `json:"message"`
Name string `json:"name,omitempty"`
Time string `json:"time"`
Stack []string `json:"stack,omitempty"`
Time *string `json:"time,omitempty"`
}

// The internal temporary object pool of the json formatter.
Expand All @@ -113,7 +115,8 @@ func putJSONFormatterObject(o *jsonFormatterObject) {
o.Level = ""
o.Message = ""
o.Name = ""
o.Time = ""
o.Stack = nil
o.Time = nil

jsonFormatterObjectPool.Put(o)
}
Expand All @@ -130,8 +133,9 @@ func (f *jsonFormatter) Format(e Entity, b *bytes.Buffer) error {
o.Level = e.Level().String()
o.Message = e.Message()
o.Name = e.Name()
o.Time = e.TimeString()

if tm := e.TimeString(); f.full || tm != "" {
o.Time = &tm
}
if fields := e.Fields(); len(fields) > 0 {
o.Fields = internal.StandardiseFieldsForJSONEncoder(fields)
} else {
Expand All @@ -142,18 +146,29 @@ func (f *jsonFormatter) Format(e Entity, b *bytes.Buffer) error {
if caller := e.Caller(); f.full || caller != "" {
o.Caller = &caller
}
if stack := e.Stack(); len(stack) > 0 {
o.Stack = stack
} else {
if f.full {
o.Stack = []string{}
}
}
// The json.Encoder.Encode method automatically adds line breaks.
return json.NewEncoder(b).Encode(o)
}

// When the json field cannot be predicted in advance, we use map to package the log data.
// Is there a better solution to improve the efficiency of json serialization?
kv := map[string]interface{}{
f.name: e.Name(),
f.time: e.TimeString(),
f.level: e.Level().String(),
f.message: e.Message(),
}
if name := e.Name(); f.full || name != "" {
kv[f.name] = name
}
if tm := e.TimeString(); f.full || tm != "" {
kv[f.time] = tm
}
if fields := e.Fields(); len(fields) > 0 {
kv[f.fields] = internal.StandardiseFieldsForJSONEncoder(fields)
} else {
Expand All @@ -164,6 +179,13 @@ func (f *jsonFormatter) Format(e Entity, b *bytes.Buffer) error {
if caller := e.Caller(); f.full || caller != "" {
kv[f.caller] = caller
}
if stack := e.Stack(); len(stack) > 0 {
kv[f.stack] = stack
} else {
if f.full {
kv[f.stack] = []string{}
}
}
// The json.Encoder.Encode method automatically adds line breaks.
return json.NewEncoder(b).Encode(kv)
}
25 changes: 23 additions & 2 deletions json_formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package logger

import (
"bytes"
"strings"
"testing"
)

Expand Down Expand Up @@ -64,7 +65,7 @@ func TestJSONFormatter_Format(t *testing.T) {
l.WithField("foo", 1).Info("test")

got := buf.String()
want := `{"caller":"","fields":{"foo":1},"level":"info","msg":"test","name":"test","time":"test"}` + "\n"
want := `{"caller":"","fields":{"foo":1},"level":"info","msg":"test","name":"test","stack":[],"time":"test"}` + "\n"
if got != want {
t.Fatalf("JSONFormatter.Format(): want %q, got %q", want, got)
}
Expand All @@ -73,7 +74,7 @@ func TestJSONFormatter_Format(t *testing.T) {
l.Info("test")

got = buf.String()
want = `{"caller":"","fields":{},"level":"info","msg":"test","name":"test","time":"test"}` + "\n"
want = `{"caller":"","fields":{},"level":"info","msg":"test","name":"test","stack":[],"time":"test"}` + "\n"
if got != want {
t.Fatalf("JSONFormatter.Format(): want %q, got %q", want, got)
}
Expand All @@ -98,3 +99,23 @@ func TestJSONFormatter_Format(t *testing.T) {
t.Fatalf("JSONFormatter.Format(): want %q, got %q", want, got)
}
}

func TestJSONFormatter_Format_WithStack(t *testing.T) {
l := New("test")
l.SetFormatter(DefaultJSONFormatter())
buf := new(bytes.Buffer)
l.SetOutput(buf)
l.SetDefaultTimeFormat("")

l.WithStack().Info("test")
if !strings.Contains(buf.String(), "TestJSONFormatter_Format_WithStack") {
t.Fatalf("JSONFormatter.Format(): %s", buf.String())
}

buf.Reset()
l.SetFormatter(MustNewJSONFormatter(map[string]string{"message": "msg"}, true))
l.WithStack().Info("test")
if !strings.Contains(buf.String(), "TestJSONFormatter_Format_WithStack") {
t.Fatalf("JSONFormatter.Format(): %s", buf.String())
}
}

0 comments on commit cc3802b

Please sign in to comment.