trpc.group/trpc-go/trpc-go@v1.0.2/log/zaplogger_test.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package log_test 15 16 import ( 17 "errors" 18 "fmt" 19 "runtime" 20 "testing" 21 "time" 22 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 "go.uber.org/zap" 26 "go.uber.org/zap/zapcore" 27 "go.uber.org/zap/zaptest/observer" 28 29 "trpc.group/trpc-go/trpc-go/log" 30 "trpc.group/trpc-go/trpc-go/plugin" 31 ) 32 33 func TestNewZapLog(t *testing.T) { 34 logger := log.NewZapLog(defaultConfig) 35 assert.NotNil(t, logger) 36 37 logger.SetLevel("0", log.LevelInfo) 38 lvl := logger.GetLevel("0") 39 assert.Equal(t, lvl, log.LevelInfo) 40 41 l := logger.With(log.Field{Key: "test", Value: "a"}) 42 l.SetLevel("output", log.LevelDebug) 43 assert.Equal(t, log.LevelDebug, l.GetLevel("output")) 44 } 45 46 func TestNewZapLog_WriteMode(t *testing.T) { 47 logDir := t.TempDir() 48 t.Run("invalid write mode", func(t *testing.T) { 49 const invalidWriteMode = 4 50 require.Panics(t, func() { 51 log.NewZapLog([]log.OutputConfig{{ 52 Writer: log.OutputFile, 53 WriteConfig: log.WriteConfig{ 54 LogPath: logDir, 55 Filename: "trpc.log", 56 WriteMode: invalidWriteMode, 57 }, 58 }}) 59 }) 60 }) 61 t.Run("valid write mode", func(t *testing.T) { 62 const ( 63 syncFileName = "trpc.syncLog" 64 asyncFileName = "trpc.asyncLog" 65 fastFileName = "trpc.fastLog" 66 ) 67 tests := []struct { 68 name string 69 config log.OutputConfig 70 }{ 71 {"sync", log.OutputConfig{ 72 Writer: log.OutputFile, 73 WriteConfig: log.WriteConfig{ 74 LogPath: logDir, 75 Filename: syncFileName, 76 WriteMode: log.WriteSync, 77 }, 78 }}, 79 {"async", log.OutputConfig{ 80 Writer: log.OutputFile, 81 WriteConfig: log.WriteConfig{ 82 LogPath: logDir, 83 Filename: asyncFileName, 84 WriteMode: log.WriteAsync, 85 }, 86 }}, 87 {"fast", log.OutputConfig{ 88 Writer: log.OutputFile, 89 WriteConfig: log.WriteConfig{ 90 LogPath: logDir, 91 Filename: fastFileName, 92 WriteMode: log.WriteFast, 93 }, 94 }}, 95 } 96 for _, tt := range tests { 97 t.Run(tt.name, func(t *testing.T) { 98 require.NotNil(t, log.NewZapLog([]log.OutputConfig{tt.config})) 99 }) 100 } 101 }) 102 } 103 104 func TestZapLogWithLevel(t *testing.T) { 105 logger := log.NewZapLog(defaultConfig) 106 assert.NotNil(t, logger) 107 108 l := logger.With(log.Field{Key: "test", Value: "a"}) 109 l.SetLevel("0", log.LevelFatal) 110 assert.Equal(t, log.LevelFatal, l.GetLevel("0")) 111 112 l = l.With(log.Field{Key: "key1", Value: "val1"}) 113 l.SetLevel("0", log.LevelError) 114 assert.Equal(t, log.LevelError, l.GetLevel("0")) 115 } 116 117 func BenchmarkDefaultTimeFormat(b *testing.B) { 118 t := time.Now() 119 for i := 0; i < b.N; i++ { 120 log.DefaultTimeFormat(t) 121 } 122 } 123 124 func BenchmarkCustomTimeFormat(b *testing.B) { 125 t := time.Now() 126 for i := 0; i < b.N; i++ { 127 log.CustomTimeFormat(t, "2006-01-02 15:04:05.000") 128 } 129 } 130 131 func TestCustomTimeFormat(t *testing.T) { 132 date := time.Date(2006, 1, 2, 15, 4, 5, 0, time.Local) 133 dateStr := log.CustomTimeFormat(date, "2006-01-02 15:04:05.000") 134 assert.Equal(t, dateStr, "2006-01-02 15:04:05.000") 135 } 136 137 func TestDefaultTimeFormat(t *testing.T) { 138 date := time.Date(2006, 1, 2, 15, 4, 5, 0, time.Local) 139 dateStr := string(log.DefaultTimeFormat(date)) 140 assert.Equal(t, dateStr, "2006-01-02 15:04:05.000") 141 } 142 143 func TestGetLogEncoderKey(t *testing.T) { 144 tests := []struct { 145 name string 146 defKey string 147 key string 148 want string 149 }{ 150 {"custom", "T", "Time", "Time"}, 151 {"default", "T", "", "T"}, 152 } 153 154 for _, tt := range tests { 155 t.Run(tt.name, func(t *testing.T) { 156 if got := log.GetLogEncoderKey(tt.defKey, tt.key); got != tt.want { 157 assert.Equal(t, got, tt.want) 158 } 159 }) 160 } 161 } 162 163 func TestNewTimeEncoder(t *testing.T) { 164 encoder := log.NewTimeEncoder("") 165 assert.NotNil(t, encoder) 166 167 encoder = log.NewTimeEncoder("2006-01-02 15:04:05") 168 assert.NotNil(t, encoder) 169 170 tests := []struct { 171 name string 172 fmt string 173 }{ 174 {"seconds timestamp", "seconds"}, 175 {"milliseconds timestamp", "milliseconds"}, 176 {"nanoseconds timestamp", "nanoseconds"}, 177 } 178 179 for _, tt := range tests { 180 t.Run(tt.name, func(t *testing.T) { 181 got := log.NewTimeEncoder(tt.fmt) 182 assert.NotNil(t, got) 183 }) 184 } 185 } 186 187 func TestWithFields(t *testing.T) { 188 // register Writer. 189 // use zap observer to support test. 190 core, ob := observer.New(zap.InfoLevel) 191 log.RegisterWriter(observewriter, &observeWriter{core: core}) 192 193 // config is configuration. 194 cfg := []log.OutputConfig{ 195 { 196 Writer: observewriter, 197 }, 198 } 199 200 // create a zap logger. 201 zl := log.NewZapLog(cfg) 202 assert.NotNil(t, zl) 203 204 // test With. 205 field := log.Field{Key: "abc", Value: int32(123)} 206 logger := zl.With(field) 207 assert.NotNil(t, logger) 208 log.SetLogger(logger) 209 log.Warn("with fields warning") 210 assert.Equal(t, 1, ob.Len()) 211 entry := ob.All()[0] 212 assert.Equal(t, zap.WarnLevel, entry.Level) 213 assert.Equal(t, "with fields warning", entry.Message) 214 assert.Equal(t, []zapcore.Field{{Key: "abc", Type: zapcore.Int32Type, Integer: 123}}, entry.Context) 215 } 216 217 func TestOptionLogger2(t *testing.T) { 218 t.Run("test option logger add caller skip", func(t *testing.T) { 219 core, ob := observer.New(zap.InfoLevel) 220 log.RegisterWriter(observewriter, &observeWriter{core: core}) 221 cfg := []log.OutputConfig{{Writer: observewriter}} 222 223 l := log.NewZapLogWithCallerSkip(cfg, 1) 224 l.Info("this is option logger test, the current caller skip is correct") 225 226 _, file, _, ok := runtime.Caller(0) 227 require.True(t, ok) 228 require.Equal(t, file, ob.All()[0].Caller.File) 229 230 ol, ok := l.(log.OptionLogger) 231 require.True(t, ok) 232 l = ol.WithOptions(log.WithAdditionalCallerSkip(1)) 233 l.Info("this is option logger test, the current caller skip is incorrect(added 1)") 234 235 _, file, _, ok = runtime.Caller(1) 236 require.True(t, ok) 237 require.Equal(t, file, ob.All()[1].Caller.File) 238 }) 239 t.Run("test option logger wrapper add caller skip", func(t *testing.T) { 240 core, ob := observer.New(zap.InfoLevel) 241 log.RegisterWriter(observewriter, &observeWriter{core: core}) 242 cfg := []log.OutputConfig{{Writer: observewriter}} 243 244 l := log.NewZapLogWithCallerSkip(cfg, 1) 245 l = l.With(log.Field{Key: "k", Value: "v"}) 246 l.Info("this is option logger wrapper test, the current caller skip is correct") 247 248 _, file, _, ok := runtime.Caller(0) 249 require.True(t, ok) 250 require.Equal(t, file, ob.All()[0].Caller.File) 251 252 ol, ok := l.(log.OptionLogger) 253 require.True(t, ok) 254 l = ol.WithOptions(log.WithAdditionalCallerSkip(1)) 255 l.Info("this is option logger wrapper test, the current caller skip is incorrect(added 1)") 256 257 _, file, _, ok = runtime.Caller(1) 258 require.True(t, ok) 259 require.Equal(t, file, ob.All()[1].Caller.File) 260 }) 261 } 262 263 const observewriter = "observewriter" 264 265 type observeWriter struct { 266 core zapcore.Core 267 } 268 269 func (f *observeWriter) Type() string { return "log" } 270 271 func (f *observeWriter) Setup(name string, dec plugin.Decoder) error { 272 if dec == nil { 273 return errors.New("empty decoder") 274 } 275 decoder, ok := dec.(*log.Decoder) 276 if !ok { 277 return errors.New("invalid decoder") 278 } 279 decoder.Core = f.core 280 decoder.ZapLevel = zap.NewAtomicLevel() 281 return nil 282 } 283 284 func TestLogLevel(t *testing.T) { 285 config := []log.OutputConfig{ 286 { 287 Writer: "console", 288 Level: "", 289 }, 290 { 291 Writer: "console", 292 Level: "trace", 293 }, 294 { 295 Writer: "console", 296 Level: "debug", 297 }, 298 { 299 Writer: "console", 300 Level: "info", 301 }, 302 { 303 Writer: "console", 304 Level: "warn", 305 }, 306 { 307 Writer: "console", 308 Level: "error", 309 }, 310 { 311 Writer: "console", 312 Level: "fatal", 313 }, 314 } 315 l := log.NewZapLog(config) 316 317 var ( 318 got []string 319 want []string 320 ) 321 for i, c := range config { 322 got = append(got, log.LevelStrings[l.GetLevel(fmt.Sprint(i))]) 323 want = append(want, log.Levels[c.Level].String()) 324 } 325 require.Equal(t, want, got) 326 } 327 328 func TestLogEnableColor(t *testing.T) { 329 cfg := []log.OutputConfig{{Writer: "console", Level: "trace", EnableColor: true}} 330 l := log.NewZapLog(cfg) 331 l.Trace("hello") 332 l.Debug("hello") 333 l.Info("hello") 334 l.Warn("hello") 335 l.Error("hello") 336 }