github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/zlog/logfmt_encoder_test.go (about) 1 package zlog 2 3 import ( 4 "math" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "go.uber.org/zap" 10 "go.uber.org/zap/buffer" 11 "go.uber.org/zap/zapcore" 12 ) 13 14 func TestEncoderObjectFields(t *testing.T) { 15 tests := []struct { 16 desc string 17 expected string 18 f func(zapcore.Encoder) 19 }{ 20 {"binary", `k="YWIxMg=="`, func(e zapcore.Encoder) { e.AddBinary("k", []byte("ab12")) }}, 21 {"bool", `k\\=true`, func(e zapcore.Encoder) { e.AddBool(`k\`, true) }}, // test key escaping once 22 {"bool", `k=true`, func(e zapcore.Encoder) { e.AddBool("k", true) }}, 23 {"bool", `k=false`, func(e zapcore.Encoder) { e.AddBool("k", false) }}, 24 {"byteString", `k=v\\`, func(e zapcore.Encoder) { e.AddByteString(`k`, []byte(`v\`)) }}, 25 {"byteString", `k=v`, func(e zapcore.Encoder) { e.AddByteString("k", []byte("v")) }}, 26 {"byteString", `k=`, func(e zapcore.Encoder) { e.AddByteString("k", []byte{}) }}, 27 {"byteString", `k=`, func(e zapcore.Encoder) { e.AddByteString("k", nil) }}, 28 {"byteString", `k="a b"`, func(e zapcore.Encoder) { e.AddByteString("k", []byte("a b")) }}, 29 {"complex128", `k=1+2i`, func(e zapcore.Encoder) { e.AddComplex128("k", 1+2i) }}, 30 {"complex64", `k=1+2i`, func(e zapcore.Encoder) { e.AddComplex64("k", 1+2i) }}, 31 {"duration", `k=0.000000001`, func(e zapcore.Encoder) { e.AddDuration("k", 1) }}, 32 {"float64", `k=1`, func(e zapcore.Encoder) { e.AddFloat64("k", 1.0) }}, 33 {"float64", `k=10000000000`, func(e zapcore.Encoder) { e.AddFloat64("k", 1e10) }}, 34 {"float64", `k=NaN`, func(e zapcore.Encoder) { e.AddFloat64("k", math.NaN()) }}, 35 {"float64", `k=+Inf`, func(e zapcore.Encoder) { e.AddFloat64("k", math.Inf(1)) }}, 36 {"float64", `k=-Inf`, func(e zapcore.Encoder) { e.AddFloat64("k", math.Inf(-1)) }}, 37 {"float32", `k=1`, func(e zapcore.Encoder) { e.AddFloat32("k", 1.0) }}, 38 {"float32", `k=10000000000`, func(e zapcore.Encoder) { e.AddFloat32("k", 1e10) }}, 39 {"float32", `k=NaN`, func(e zapcore.Encoder) { e.AddFloat32("k", float32(math.NaN())) }}, 40 {"float32", `k=+Inf`, func(e zapcore.Encoder) { e.AddFloat32("k", float32(math.Inf(1))) }}, 41 {"float32", `k=-Inf`, func(e zapcore.Encoder) { e.AddFloat32("k", float32(math.Inf(-1))) }}, 42 {"int", `k=42`, func(e zapcore.Encoder) { e.AddInt("k", 42) }}, 43 {"int64", `k=42`, func(e zapcore.Encoder) { e.AddInt64("k", 42) }}, 44 {"int32", `k=42`, func(e zapcore.Encoder) { e.AddInt32("k", 42) }}, 45 {"int16", `k=42`, func(e zapcore.Encoder) { e.AddInt16("k", 42) }}, 46 {"int8", `k=42`, func(e zapcore.Encoder) { e.AddInt8("k", 42) }}, 47 {"string", `k=v\\`, func(e zapcore.Encoder) { e.AddString(`k`, `v\`) }}, 48 {"string", `k=v`, func(e zapcore.Encoder) { e.AddString("k", "v") }}, 49 {"string", `k=`, func(e zapcore.Encoder) { e.AddString("k", "") }}, 50 {"string", `k="a b"`, func(e zapcore.Encoder) { e.AddString("k", "a b") }}, 51 {"time", `k=1`, func(e zapcore.Encoder) { e.AddTime("k", time.Unix(1, 0)) }}, 52 {"uint", `k=42`, func(e zapcore.Encoder) { e.AddUint("k", 42) }}, 53 {"uint64", `k=42`, func(e zapcore.Encoder) { e.AddUint64("k", 42) }}, 54 {"uint32", `k=42`, func(e zapcore.Encoder) { e.AddUint32("k", 42) }}, 55 {"uint16", `k=42`, func(e zapcore.Encoder) { e.AddUint16("k", 42) }}, 56 {"uint8", `k=42`, func(e zapcore.Encoder) { e.AddUint8("k", 42) }}, 57 {"uintptr", `k=42`, func(e zapcore.Encoder) { e.AddUintptr("k", 42) }}, 58 { 59 desc: "array (success)", 60 expected: `k=a,b`, 61 f: func(e zapcore.Encoder) { 62 assert.NoError( 63 t, 64 e.AddArray(`k`, zapcore.ArrayMarshalerFunc(func(enc zapcore.ArrayEncoder) error { 65 for _, s := range []string{"a", "b"} { 66 enc.AppendString(s) 67 } 68 return nil 69 }), 70 ), 71 "Unexpected error calling MarshalLogArray.", 72 ) 73 }, 74 }, 75 { 76 desc: "namespace", 77 expected: `outermost.outer.foo=1 outermost.outer.inner.foo=2`, 78 f: func(e zapcore.Encoder) { 79 e.OpenNamespace("outermost") 80 e.OpenNamespace("outer") 81 e.AddInt("foo", 1) 82 e.OpenNamespace("inner") 83 e.AddInt("foo", 2) 84 e.OpenNamespace("innermost") 85 }, 86 }, 87 {"reflected slice", "k=a,b", func(e zapcore.Encoder) { e.AddReflected("k", []string{"a", "b"}) }}, 88 {"reflected slice of int", "k=1,2,3", func(e zapcore.Encoder) { e.AddReflected("k", []int16{1, 2, 3}) }}, 89 {"reflected array", "k=a,b", func(e zapcore.Encoder) { e.AddReflected("k", [2]string{"a", "b"}) }}, 90 } 91 92 for _, tt := range tests { 93 assertOutput(t, tt.desc, tt.expected, tt.f) 94 } 95 } 96 97 func assertOutput(t testing.TB, desc string, expected string, f func(zapcore.Encoder)) { 98 enc := &logfmtEncoder{buf: bufferpool.Get(), EncoderConfig: &zapcore.EncoderConfig{ 99 EncodeTime: zapcore.EpochTimeEncoder, 100 EncodeDuration: zapcore.SecondsDurationEncoder, 101 }} 102 f(enc) 103 assert.Equal(t, expected, enc.buf.String(), "Unexpected encoder output after adding a %s.", desc) 104 105 enc.truncate() 106 enc.AddString("foo", "bar") 107 f(enc) 108 expectedPrefix := `foo=bar` 109 if expected != "" { 110 // If we expect output, it should be comma-separated from the previous 111 // field. 112 expectedPrefix += " " 113 } 114 assert.Equal(t, expectedPrefix+expected, enc.buf.String(), "Unexpected encoder output after adding a %s as a second field.", desc) 115 } 116 117 func TestEncodeCaller(t *testing.T) { 118 enc := &logfmtEncoder{buf: bufferpool.Get(), EncoderConfig: &zapcore.EncoderConfig{ 119 EncodeTime: zapcore.EpochTimeEncoder, 120 EncodeDuration: zapcore.SecondsDurationEncoder, 121 EncodeCaller: zapcore.ShortCallerEncoder, 122 }} 123 124 var buf *buffer.Buffer 125 var err error 126 encodeEntry := func() { 127 buf, err = enc.EncodeEntry( 128 zapcore.Entry{ 129 Level: zapcore.DebugLevel, 130 Time: time.Time{}, 131 LoggerName: "test", 132 Message: "caller test", 133 Caller: zapcore.EntryCaller{ 134 Defined: true, 135 File: "h2g2.go", 136 Line: 42, 137 }, 138 }, 139 []zapcore.Field{ 140 zap.String("k", "v"), 141 }, 142 ) 143 } 144 145 encodeEntry() 146 assert.Nil(t, err) 147 assert.Equal(t, "k=v\n", buf.String()) 148 149 enc.truncate() 150 enc.EncoderConfig.CallerKey = "caller" 151 encodeEntry() 152 assert.Nil(t, err) 153 assert.Equal(t, "caller=h2g2.go:42 k=v\n", buf.String()) 154 } 155 156 func TestEncodeStacktrace(t *testing.T) { 157 enc := &logfmtEncoder{buf: bufferpool.Get(), EncoderConfig: &zapcore.EncoderConfig{ 158 EncodeTime: zapcore.EpochTimeEncoder, 159 EncodeDuration: zapcore.SecondsDurationEncoder, 160 }} 161 162 var buf *buffer.Buffer 163 var err error 164 encodeEntry := func() { 165 buf, err = enc.EncodeEntry( 166 zapcore.Entry{ 167 Level: zapcore.DebugLevel, 168 Time: time.Time{}, 169 LoggerName: "test", 170 Message: "stacktrace test", 171 Stack: `panic: an unexpected error occurred 172 173 goroutine 1 [running]: 174 main.main() 175 /go/src/github.com/jsternberg/myawesomeproject/h2g2.go:4 +0x39 176 `, 177 }, 178 []zapcore.Field{ 179 zap.String("k", "v"), 180 }, 181 ) 182 } 183 184 encodeEntry() 185 assert.Nil(t, err) 186 assert.Equal(t, "k=v\n", buf.String()) 187 188 enc.truncate() 189 enc.EncoderConfig.StacktraceKey = "stacktrace" 190 encodeEntry() 191 assert.Nil(t, err) 192 assert.Equal(t, `k=v stacktrace="panic: an unexpected error occurred\n\ngoroutine 1 [running]:\nmain.main()\n\t\t/go/src/github.com/jsternberg/myawesomeproject/h2g2.go:4 +0x39\n" 193 `, buf.String()) 194 }