Skip to content

Commit b4f500c

Browse files
Fix field marshaller (#73)
1 parent 79fd0af commit b4f500c

File tree

4 files changed

+81
-15
lines changed

4 files changed

+81
-15
lines changed

field.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package logger
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"strconv"
67
"strings"
@@ -106,6 +107,22 @@ func (f *Field) String() string {
106107
}
107108
}
108109

110+
// MarshalJSON was called by json.Marshal(field)
111+
// json Marshaller interface
112+
func (f *Field) MarshalJSON() ([]byte, error) {
113+
if marshallable, ok := f.Value.(json.Marshaler); ok {
114+
return marshallable.MarshalJSON()
115+
}
116+
switch f.Type {
117+
case BoolType, Int8Type, Int16Type, Int32Type, Int64Type, Uint8Type, Uint16Type, Uint32Type, Uint64Type, UintptrType, Float32Type, Float64Type:
118+
return []byte(f.String()), nil
119+
case SkipType, Complex64Type, Complex128Type, StringType, BinaryType, ByteStringType, ErrorType, TimeType, DurationType, StringerType:
120+
return strconv.AppendQuote([]byte{}, f.String()), nil
121+
default:
122+
return json.Marshal(f.Value)
123+
}
124+
}
125+
109126
// GoString was called by fmt.Printf("%#v", Fields)
110127
// fmt GoStringer interface
111128
func (f *Field) GoString() string {
@@ -118,7 +135,6 @@ func (f *Field) GoString() string {
118135
builder.WriteString(strconv.FormatUint(uint64(f.Type), 10))
119136
builder.WriteString("}")
120137
return builder.String()
121-
122138
}
123139

124140
// Skip will create Skip Field

field_test.go

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestField(t *testing.T) {
4949
{field: logger.ByteString("ByteString field", []byte("my_value")), expectedValue: []byte("my_value"), expectedType: logger.ByteStringType},
5050
{field: logger.Error("Error field", err), expectedValue: err, expectedType: logger.ErrorType},
5151
{field: logger.Time("Time field", now), expectedValue: now, expectedType: logger.TimeType},
52-
{field: logger.Duration("Duration field", 5 * time.Second), expectedValue: 5 * time.Second, expectedType: logger.DurationType},
52+
{field: logger.Duration("Duration field", 5*time.Second), expectedValue: 5 * time.Second, expectedType: logger.DurationType},
5353
{field: logger.Stringer("Stringer field", MyStringer{}), expectedValue: MyStringer{}, expectedType: logger.StringerType},
5454
{field: logger.Reflect("Reflect field", struct{}{}), expectedValue: struct{}{}, expectedType: logger.ReflectType},
5555
}
@@ -64,9 +64,9 @@ func TestField(t *testing.T) {
6464

6565
func TestField_Any(t *testing.T) {
6666
tests := []struct {
67-
name string
68-
value interface{}
69-
expectedType logger.FieldType
67+
name string
68+
value interface{}
69+
expectedType logger.FieldType
7070
}{
7171
{name: "my bool", value: true, expectedType: logger.BoolType},
7272
{name: "my bool", value: false, expectedType: logger.BoolType},
@@ -124,14 +124,14 @@ func TestField_String(t *testing.T) {
124124
{field: logger.Uintptr("Uintptr field", 123), expectedString: "123"},
125125
{field: logger.Float32("Float32 field", 1.23456789), expectedString: "1.234567881"},
126126
{field: logger.Float64("Float64 field", 123.4567891011), expectedString: "123.4567891"},
127-
{field: logger.Complex64("Complex64 field", 6 + 7i), expectedString: "(6+7i)"},
128-
{field: logger.Complex128("Complex128 field", 6 + 7i), expectedString: "(6+7i)"},
127+
{field: logger.Complex64("Complex64 field", 6+7i), expectedString: "(6+7i)"},
128+
{field: logger.Complex128("Complex128 field", 6+7i), expectedString: "(6+7i)"},
129129
{field: logger.String("String field", "my_value"), expectedString: "my_value"},
130130
{field: logger.Binary("Binary field", []byte{1, 2, 3}), expectedString: "\x01\x02\x03"},
131131
{field: logger.ByteString("ByteString field", []byte("my_value")), expectedString: "my_value"},
132132
{field: logger.Error("Error field", err), expectedString: "my_error_value"},
133133
{field: logger.Time("Time field", now), expectedString: now.String()},
134-
{field: logger.Duration("Duration field", 5 * time.Second), expectedString: "5s"},
134+
{field: logger.Duration("Duration field", 5*time.Second), expectedString: "5s"},
135135
{field: logger.Stringer("Stringer field", MyStringer{}), expectedString: "my_stringer"},
136136
{field: logger.Reflect("Reflect field", struct{}{}), expectedString: "{}"},
137137
}
@@ -143,6 +143,51 @@ func TestField_String(t *testing.T) {
143143
}
144144
}
145145

146+
func TestField_MarshalJSON(t *testing.T) {
147+
now := time.Now()
148+
nowMarshalled, _ := now.MarshalJSON()
149+
err := errors.New("my_error_value")
150+
151+
tests := []struct {
152+
name string
153+
field logger.Field
154+
expectedString string
155+
}{
156+
{field: logger.Skip("Skip field", "my_value"), expectedString: `"<skipped>"`},
157+
{field: logger.Bool("Bool field", true), expectedString: "true"},
158+
{field: logger.Bool("Bool field", false), expectedString: "false"},
159+
{field: logger.Int8("Int8 field", 123), expectedString: "123"},
160+
{field: logger.Int16("Int16 field", 123), expectedString: "123"},
161+
{field: logger.Int32("Int32 field", 123), expectedString: "123"},
162+
{field: logger.Int64("Int64 field", 123), expectedString: "123"},
163+
{field: logger.Uint8("Uint8 field", 123), expectedString: "123"},
164+
{field: logger.Uint16("Uint16 field", 123), expectedString: "123"},
165+
{field: logger.Uint32("Uint32 field", 123), expectedString: "123"},
166+
{field: logger.Uint64("Uint64 field", 123), expectedString: "123"},
167+
{field: logger.Uintptr("Uintptr field", 123), expectedString: "123"},
168+
{field: logger.Float32("Float32 field", 1.23456789), expectedString: "1.234567881"},
169+
{field: logger.Float64("Float64 field", 123.4567891011), expectedString: "123.4567891"},
170+
{field: logger.Complex64("Complex64 field", 6+7i), expectedString: `"(6+7i)"`},
171+
{field: logger.Complex128("Complex128 field", 6+7i), expectedString: `"(6+7i)"`},
172+
{field: logger.String("String field", "my_value"), expectedString: `"my_value"`},
173+
{field: logger.Binary("Binary field", []byte{1, 2, 3}), expectedString: `"\x01\x02\x03"`},
174+
{field: logger.ByteString("ByteString field", []byte("my_value")), expectedString: `"my_value"`},
175+
{field: logger.Error("Error field", err), expectedString: `"my_error_value"`},
176+
{field: logger.Time("Time field", now), expectedString: string(nowMarshalled)},
177+
{field: logger.Duration("Duration field", 5*time.Second), expectedString: `"5s"`},
178+
{field: logger.Stringer("Stringer field", MyStringer{}), expectedString: `"my_stringer"`},
179+
{field: logger.Reflect("Reflect field", struct{}{}), expectedString: "{}"},
180+
}
181+
182+
for _, tt := range tests {
183+
t.Run(tt.field.Name, func(t *testing.T) {
184+
result, err := tt.field.MarshalJSON()
185+
assert.NoError(t, err)
186+
assert.Equal(t, tt.expectedString, string(result))
187+
})
188+
}
189+
}
190+
146191
func TestField_GoString(t *testing.T) {
147192
now := time.Now()
148193
error := errors.New("my_error_value")
@@ -166,14 +211,14 @@ func TestField_GoString(t *testing.T) {
166211
{field: logger.Uintptr("Uintptr field", 123), expectedGoString: "logger.Field{Name: Uintptr field, Value: 123, Type: 11}"},
167212
{field: logger.Float32("Float32 field", 1.23456789), expectedGoString: "logger.Field{Name: Float32 field, Value: 1.234567881, Type: 12}"},
168213
{field: logger.Float64("Float64 field", 123.4567891011), expectedGoString: "logger.Field{Name: Float64 field, Value: 123.4567891, Type: 13}"},
169-
{field: logger.Complex64("Complex64 field", 6 + 7i), expectedGoString: "logger.Field{Name: Complex64 field, Value: (6+7i), Type: 14}"},
170-
{field: logger.Complex128("Complex128 field", 6 + 7i), expectedGoString: "logger.Field{Name: Complex128 field, Value: (6+7i), Type: 15}"},
214+
{field: logger.Complex64("Complex64 field", 6+7i), expectedGoString: "logger.Field{Name: Complex64 field, Value: (6+7i), Type: 14}"},
215+
{field: logger.Complex128("Complex128 field", 6+7i), expectedGoString: "logger.Field{Name: Complex128 field, Value: (6+7i), Type: 15}"},
171216
{field: logger.String("String field", "my_value"), expectedGoString: "logger.Field{Name: String field, Value: my_value, Type: 16}"},
172217
{field: logger.Binary("Binary field", []byte{1, 2, 3}), expectedGoString: "logger.Field{Name: Binary field, Value: \x01\x02\x03, Type: 17}"},
173218
{field: logger.ByteString("ByteString field", []byte("my_value")), expectedGoString: "logger.Field{Name: ByteString field, Value: my_value, Type: 18}"},
174219
{field: logger.Error("Error field", error), expectedGoString: "logger.Field{Name: Error field, Value: my_error_value, Type: 19}"},
175-
{field: logger.Time("Time field", now), expectedGoString: "logger.Field{Name: Time field, Value: "+now.String()+", Type: 20}"},
176-
{field: logger.Duration("Duration field", 5 * time.Second), expectedGoString: "logger.Field{Name: Duration field, Value: 5s, Type: 21}"},
220+
{field: logger.Time("Time field", now), expectedGoString: "logger.Field{Name: Time field, Value: " + now.String() + ", Type: 20}"},
221+
{field: logger.Duration("Duration field", 5*time.Second), expectedGoString: "logger.Field{Name: Duration field, Value: 5s, Type: 21}"},
177222
{field: logger.Stringer("Stringer field", MyStringer{}), expectedGoString: "logger.Field{Name: Stringer field, Value: my_stringer, Type: 22}"},
178223
{field: logger.Reflect("Reflect field", struct{}{}), expectedGoString: "logger.Field{Name: Reflect field, Value: {}, Type: 23}"},
179224
}

formatter/json.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package formatter
22

33
import (
4-
"encoding/json"
54
"strconv"
65
"strings"
76

@@ -47,8 +46,8 @@ func ContextToJSON(context *logger.Context, builder *strings.Builder) {
4746
builder.WriteRune('"')
4847
builder.WriteString(name)
4948
builder.WriteString("\":")
50-
d, _ := json.Marshal(field.Value)
51-
builder.WriteString(string(d))
49+
d, _ := field.MarshalJSON()
50+
builder.Write(d)
5251
i++
5352
}
5453
builder.WriteString("}")

formatter/json_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package formatter_test
22

33
import (
4+
"errors"
45
"fmt"
56
"strings"
67
"testing"
@@ -65,6 +66,11 @@ func TestMarshalContextTo(t *testing.T) {
6566
context: logger.NewContext().Add("my_key", time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC)),
6667
expectedStrings: []string{`my_key":"2020-01-02T03:04:05.000000006Z"`},
6768
},
69+
{
70+
name: "test time message with context",
71+
context: logger.NewContext().Add("my_key", errors.New("my error message")),
72+
expectedStrings: []string{`my_key":"my error message"`},
73+
},
6874
}
6975

7076
for _, tt := range tests {

0 commit comments

Comments
 (0)