Skip to content

Commit cc3802b

Browse files
committed
Add call stack for json formatter.
1 parent 9c0d4d8 commit cc3802b

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

json_formatter.go

+30-8
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func DefaultJSONFormatter() Formatter {
3838
func NewJSONFormatter(keys map[string]string, full bool) (Formatter, error) {
3939
m := map[string]string{
4040
"name": "name", "time": "time", "level": "level", "message": "message",
41-
"fields": "fields", "caller": "caller",
41+
"fields": "fields", "caller": "caller", "stack": "stack",
4242
}
4343

4444
structure := true
@@ -56,7 +56,7 @@ func NewJSONFormatter(keys map[string]string, full bool) (Formatter, error) {
5656
}
5757
f := &jsonFormatter{
5858
name: m["name"], time: m["time"], level: m["level"], message: m["message"],
59-
fields: m["fields"], caller: m["caller"],
59+
fields: m["fields"], caller: m["caller"], stack: m["stack"],
6060
full: full, structure: structure,
6161
}
6262
return f, nil
@@ -79,6 +79,7 @@ type jsonFormatter struct {
7979
message string
8080
fields string
8181
caller string
82+
stack string
8283
full bool
8384
structure bool
8485
}
@@ -91,7 +92,8 @@ type jsonFormatterObject struct {
9192
Level string `json:"level"`
9293
Message string `json:"message"`
9394
Name string `json:"name,omitempty"`
94-
Time string `json:"time"`
95+
Stack []string `json:"stack,omitempty"`
96+
Time *string `json:"time,omitempty"`
9597
}
9698

9799
// The internal temporary object pool of the json formatter.
@@ -113,7 +115,8 @@ func putJSONFormatterObject(o *jsonFormatterObject) {
113115
o.Level = ""
114116
o.Message = ""
115117
o.Name = ""
116-
o.Time = ""
118+
o.Stack = nil
119+
o.Time = nil
117120

118121
jsonFormatterObjectPool.Put(o)
119122
}
@@ -130,8 +133,9 @@ func (f *jsonFormatter) Format(e Entity, b *bytes.Buffer) error {
130133
o.Level = e.Level().String()
131134
o.Message = e.Message()
132135
o.Name = e.Name()
133-
o.Time = e.TimeString()
134-
136+
if tm := e.TimeString(); f.full || tm != "" {
137+
o.Time = &tm
138+
}
135139
if fields := e.Fields(); len(fields) > 0 {
136140
o.Fields = internal.StandardiseFieldsForJSONEncoder(fields)
137141
} else {
@@ -142,18 +146,29 @@ func (f *jsonFormatter) Format(e Entity, b *bytes.Buffer) error {
142146
if caller := e.Caller(); f.full || caller != "" {
143147
o.Caller = &caller
144148
}
149+
if stack := e.Stack(); len(stack) > 0 {
150+
o.Stack = stack
151+
} else {
152+
if f.full {
153+
o.Stack = []string{}
154+
}
155+
}
145156
// The json.Encoder.Encode method automatically adds line breaks.
146157
return json.NewEncoder(b).Encode(o)
147158
}
148159

149160
// When the json field cannot be predicted in advance, we use map to package the log data.
150161
// Is there a better solution to improve the efficiency of json serialization?
151162
kv := map[string]interface{}{
152-
f.name: e.Name(),
153-
f.time: e.TimeString(),
154163
f.level: e.Level().String(),
155164
f.message: e.Message(),
156165
}
166+
if name := e.Name(); f.full || name != "" {
167+
kv[f.name] = name
168+
}
169+
if tm := e.TimeString(); f.full || tm != "" {
170+
kv[f.time] = tm
171+
}
157172
if fields := e.Fields(); len(fields) > 0 {
158173
kv[f.fields] = internal.StandardiseFieldsForJSONEncoder(fields)
159174
} else {
@@ -164,6 +179,13 @@ func (f *jsonFormatter) Format(e Entity, b *bytes.Buffer) error {
164179
if caller := e.Caller(); f.full || caller != "" {
165180
kv[f.caller] = caller
166181
}
182+
if stack := e.Stack(); len(stack) > 0 {
183+
kv[f.stack] = stack
184+
} else {
185+
if f.full {
186+
kv[f.stack] = []string{}
187+
}
188+
}
167189
// The json.Encoder.Encode method automatically adds line breaks.
168190
return json.NewEncoder(b).Encode(kv)
169191
}

json_formatter_test.go

+23-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package logger
1616

1717
import (
1818
"bytes"
19+
"strings"
1920
"testing"
2021
)
2122

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

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

7576
got = buf.String()
76-
want = `{"caller":"","fields":{},"level":"info","msg":"test","name":"test","time":"test"}` + "\n"
77+
want = `{"caller":"","fields":{},"level":"info","msg":"test","name":"test","stack":[],"time":"test"}` + "\n"
7778
if got != want {
7879
t.Fatalf("JSONFormatter.Format(): want %q, got %q", want, got)
7980
}
@@ -98,3 +99,23 @@ func TestJSONFormatter_Format(t *testing.T) {
9899
t.Fatalf("JSONFormatter.Format(): want %q, got %q", want, got)
99100
}
100101
}
102+
103+
func TestJSONFormatter_Format_WithStack(t *testing.T) {
104+
l := New("test")
105+
l.SetFormatter(DefaultJSONFormatter())
106+
buf := new(bytes.Buffer)
107+
l.SetOutput(buf)
108+
l.SetDefaultTimeFormat("")
109+
110+
l.WithStack().Info("test")
111+
if !strings.Contains(buf.String(), "TestJSONFormatter_Format_WithStack") {
112+
t.Fatalf("JSONFormatter.Format(): %s", buf.String())
113+
}
114+
115+
buf.Reset()
116+
l.SetFormatter(MustNewJSONFormatter(map[string]string{"message": "msg"}, true))
117+
l.WithStack().Info("test")
118+
if !strings.Contains(buf.String(), "TestJSONFormatter_Format_WithStack") {
119+
t.Fatalf("JSONFormatter.Format(): %s", buf.String())
120+
}
121+
}

0 commit comments

Comments
 (0)