trpc.group/trpc-go/trpc-go@v1.0.3/log/log_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 "bytes" 18 "context" 19 "fmt" 20 "path/filepath" 21 "runtime" 22 "strconv" 23 "strings" 24 "testing" 25 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/require" 28 "go.uber.org/zap" 29 "go.uber.org/zap/zapcore" 30 31 trpc "trpc.group/trpc-go/trpc-go" 32 "trpc.group/trpc-go/trpc-go/codec" 33 "trpc.group/trpc-go/trpc-go/log" 34 ) 35 36 func TestSetLevel(t *testing.T) { 37 const level = "0" 38 log.SetLevel(level, log.LevelInfo) 39 require.Equal(t, log.LevelInfo, log.GetLevel(level)) 40 } 41 42 func TestSetLogger(t *testing.T) { 43 logger := log.NewZapLog(log.Config{}) 44 log.SetLogger(logger) 45 require.Equal(t, log.GetDefaultLogger(), logger) 46 } 47 48 func TestLogXXX(t *testing.T) { 49 log.Fatal("xxx") 50 } 51 52 func TestLoggerNil(t *testing.T) { 53 ctx := context.Background() 54 ctx, msg := codec.WithNewMessage(ctx) 55 msg.WithLogger((log.Logger)(nil)) 56 log.EnableTrace() 57 log.TraceContext(ctx, "test") 58 log.TraceContextf(ctx, "test %s", "log") 59 log.DebugContext(ctx, "test") 60 log.DebugContextf(ctx, "test %s", "log") 61 log.InfoContext(ctx, "test") 62 log.InfoContextf(ctx, "test %s", "log") 63 log.ErrorContext(ctx, "test") 64 log.ErrorContextf(ctx, "test %s", "log") 65 log.WarnContext(ctx, "test") 66 log.WarnContextf(ctx, "test %s", "log") 67 log.FatalContext(ctx, "test") 68 log.FatalContextf(ctx, "test %s", "log") 69 70 l := msg.Logger() 71 require.Nil(t, l) 72 } 73 74 func TestLoggerZapLogWrapper(t *testing.T) { 75 ctx := context.Background() 76 ctx, msg := codec.WithNewMessage(ctx) 77 msg.WithLogger(log.NewZapLog(defaultConfig)) 78 79 log.EnableTrace() 80 log.TraceContext(ctx, "test") 81 log.TraceContextf(ctx, "test") 82 log.DebugContext(ctx, "test") 83 log.DebugContextf(ctx, "test") 84 log.InfoContext(ctx, "test") 85 log.InfoContextf(ctx, "test %s", "s") 86 log.ErrorContext(ctx, "test") 87 log.ErrorContextf(ctx, "test") 88 log.WarnContext(ctx, "test") 89 log.WarnContextf(ctx, "test") 90 91 msg.WithLogger(log.NewZapLog(defaultConfig)) 92 log.WithContextFields(ctx, "a", "a") 93 log.SetLevel("console", log.LevelDebug) 94 require.Equal(t, log.GetLevel("console"), log.LevelDebug) 95 } 96 97 func TestWithContextFields(t *testing.T) { 98 ctx := trpc.BackgroundContext() 99 log.WithContextFields(ctx, "k", "v") 100 require.NotNil(t, codec.Message(ctx).Logger()) 101 102 ctx = context.Background() 103 newCtx := log.WithContextFields(ctx, "k", "v") 104 require.Nil(t, codec.Message(ctx).Logger()) 105 require.NotNil(t, codec.Message(newCtx).Logger()) 106 } 107 108 func TestOptionLogger1(t *testing.T) { 109 log.Debug("test1") 110 log.Debug("test2") 111 log.Debug("test3") 112 ctx := context.Background() 113 ctx, msg := codec.WithNewMessage(ctx) 114 msg.WithCallerServiceName("trpc.test.helloworld.Greeter") 115 log.WithContextFields(ctx, "a", "a") 116 log.TraceContext(ctx, "test") 117 log.InfoContext(ctx, "test") 118 log.WithContextFields(ctx, "b", "b") 119 log.InfoContext(ctx, "test") 120 121 trpc.Message(ctx).WithLogger(log.Get("default")) 122 log.DebugContext(ctx, "custom log msg") 123 } 124 125 func TestCustomLogger(t *testing.T) { 126 log.Register("custom", log.NewZapLogWithCallerSkip(log.Config{log.OutputConfig{Writer: "console"}}, 1)) 127 log.Get("custom").Debug("test") 128 } 129 130 const ( 131 noOptionBufLogger = "noOptionBuf" 132 customBufLogger = "customBuf" 133 ) 134 135 func getCtxFuncs() []func() context.Context { 136 return []func() context.Context{ 137 func() context.Context { 138 return context.Background() 139 }, 140 func() context.Context { 141 ctx, msg := codec.WithNewMessage(context.Background()) 142 msg.WithCallerServiceName("trpc.test.helloworld.Greeter") 143 return ctx 144 }, func() context.Context { 145 ctx, msg := codec.WithNewMessage(context.Background()) 146 msg.WithLogger(log.GetDefaultLogger()) 147 msg.WithCallerServiceName("trpc.test.helloworld.Greeter") 148 return ctx 149 }, func() context.Context { 150 ctx, msg := codec.WithNewMessage(context.Background()) 151 msg.WithLogger(log.Get(noOptionBufLogger)) 152 msg.WithCallerServiceName("trpc.test.helloworld.Greeter") 153 return ctx 154 }, 155 } 156 } 157 158 func TestWithContext(t *testing.T) { 159 old := log.GetDefaultLogger() 160 defer log.SetLogger(old) 161 for _, ctxFunc := range getCtxFuncs() { 162 ctx := ctxFunc() 163 checkTrace(t, func() { 164 log.WithContext(ctx, log.Field{Key: "123", Value: 123}).Debugf("test") 165 log.WithContext(ctx, log.Field{Key: "123", Value: 123}).With(log.Field{Key: "k2", Value: "v2"}).Debugf("test") 166 log.WithContext(ctx, log.Field{Key: "123", Value: 123}).With(log.Field{Key: "k2", Value: "v2"}).With(log.Field{Key: "k2", Value: "v2"}).Debugf("test") 167 }, nil) 168 } 169 } 170 171 func TestStacktrace(t *testing.T) { 172 checkTrace(t, func() { 173 log.Debug("test") 174 log.Error("test") 175 }, nil) 176 } 177 178 func check(t *testing.T, out *bytes.Buffer, fn func()) { 179 fn() 180 181 _, file, start, ok := runtime.Caller(2) 182 assert.True(t, ok) 183 184 pathPre := filepath.Join(filepath.Base(filepath.Dir(file)), filepath.Base(file)) + ":" 185 trace := out.String() 186 count := strings.Count(trace, pathPre) 187 fmt.Println(" line count:", count, "start:", start+1, "end:", start+count) 188 fmt.Println(trace) 189 for line := start + 1; line <= start+count; line++ { 190 path := pathPre + strconv.Itoa(line) 191 require.Contains(t, out.String(), path, "log trace error") 192 } 193 194 verifyNoZap(t, trace) 195 } 196 197 var ( 198 buf = &bytes.Buffer{} 199 ) 200 201 func init() { 202 log.Register(customBufLogger, log.NewZapBufLogger(buf, 1)) 203 log.Register(noOptionBufLogger, newNoOptionBufLogger(buf, 1)) 204 } 205 206 // checkTrace set buf log to check trace. 207 func checkTrace(t *testing.T, fn func(), setLog func()) { 208 *buf = bytes.Buffer{} 209 log.SetLogger(log.NewZapBufLogger(buf, 2)) 210 if setLog != nil { 211 setLog() 212 } 213 check(t, buf, fn) 214 } 215 216 func verifyNoZap(t *testing.T, logs string) { 217 for _, fnPrefix := range zapPackages { 218 require.NotContains(t, logs, fnPrefix, "should not contain zap package") 219 } 220 } 221 222 // zapPackages are packages that we search for in the logging output to match a 223 // zap stack frame. 224 var zapPackages = []string{ 225 "go.uber.org/zap", 226 "go.uber.org/zap/zapcore", 227 } 228 229 func TestLogFatal(t *testing.T) { 230 old := log.GetDefaultLogger() 231 defer log.SetLogger(old) 232 233 var h customWriteHook 234 log.SetLogger(log.NewZapFatalLogger(&h)) 235 log.Fatal("test") 236 assert.True(t, h.called) 237 h.called = false 238 log.Fatalf("test") 239 assert.True(t, h.called) 240 h.called = false 241 ctx := context.Background() 242 log.FatalContext(ctx, "test") 243 assert.True(t, h.called) 244 h.called = false 245 log.FatalContextf(ctx, "test") 246 assert.True(t, h.called) 247 248 ctx, msg := codec.WithNewMessage(context.Background()) 249 msg.WithLogger(log.GetDefaultLogger()) 250 msg.WithCallerServiceName("trpc.test.helloworld.Greeter") 251 h.called = false 252 log.FatalContext(ctx, "test") 253 assert.True(t, h.called) 254 h.called = false 255 log.FatalContextf(ctx, "test") 256 assert.True(t, h.called) 257 } 258 259 type customWriteHook struct { 260 called bool 261 } 262 263 func (h *customWriteHook) OnWrite(_ *zapcore.CheckedEntry, _ []zap.Field) { 264 h.called = true 265 }