github.com/rudderlabs/rudder-go-kit@v0.30.0/logger/logger_test.go (about) 1 package logger_test 2 3 import ( 4 "bufio" 5 "bytes" 6 "errors" 7 "net/http" 8 "os" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 "github.com/zenizh/go-capturer" 14 15 "github.com/rudderlabs/rudder-go-kit/config" 16 "github.com/rudderlabs/rudder-go-kit/logger" 17 ) 18 19 func Test_Print_All_Levels(t *testing.T) { 20 fileName := t.TempDir() + "out.log" 21 f, err := os.Create(fileName) 22 require.NoError(t, err) 23 defer func() { _ = f.Close() }() 24 25 c := config.New() 26 c.Set("LOG_LEVEL", "EVENT") 27 c.Set("Logger.enableConsole", false) 28 c.Set("Logger.enableFile", true) 29 c.Set("Logger.enableFileNameInLog", false) 30 c.Set("Logger.logFileLocation", fileName) 31 loggerFactory := logger.NewFactory(c, constantClockOpt) 32 33 rootLogger := loggerFactory.NewLogger() 34 require.True(t, rootLogger.IsDebugLevel()) 35 36 scanner := bufio.NewScanner(f) 37 38 rootLogger.Debug("hello ", "world") 39 require.True(t, scanner.Scan(), "it should print a log statement") 40 require.Equal(t, "2077-01-23T10:15:13.000Z DEBUG hello world", scanner.Text()) 41 42 rootLogger.Info("hello ", "world") 43 require.True(t, scanner.Scan(), "it should print a log statement") 44 require.Equal(t, "2077-01-23T10:15:13.000Z INFO hello world", scanner.Text()) 45 46 rootLogger.Warn("hello ", "world") 47 require.True(t, scanner.Scan(), "it should print a log statement") 48 require.Equal(t, "2077-01-23T10:15:13.000Z WARN hello world", scanner.Text()) 49 50 rootLogger.Error("hello ", "world") 51 require.True(t, scanner.Scan(), "it should print a log statement") 52 require.Equal(t, "2077-01-23T10:15:13.000Z ERROR hello world", scanner.Text()) 53 54 rootLogger.Fatal("hello ", "world") 55 require.True(t, scanner.Scan(), "it should print a log statement") 56 require.Equal(t, "2077-01-23T10:15:13.000Z ERROR hello world", scanner.Text()) 57 } 58 59 func Test_Printf_All_Levels(t *testing.T) { 60 fileName := t.TempDir() + "out.log" 61 f, err := os.Create(fileName) 62 require.NoError(t, err) 63 defer func() { _ = f.Close() }() 64 65 c := config.New() 66 c.Set("LOG_LEVEL", "EVENT") 67 c.Set("Logger.enableConsole", false) 68 c.Set("Logger.enableFile", true) 69 c.Set("Logger.enableFileNameInLog", false) 70 c.Set("Logger.logFileLocation", fileName) 71 loggerFactory := logger.NewFactory(c, constantClockOpt) 72 73 rootLogger := loggerFactory.NewLogger() 74 require.True(t, rootLogger.IsDebugLevel()) 75 76 scanner := bufio.NewScanner(f) 77 78 rootLogger.Debugf("hello %s", "world") 79 require.True(t, scanner.Scan(), "it should print a log statement") 80 require.Equal(t, "2077-01-23T10:15:13.000Z DEBUG hello world", scanner.Text()) 81 82 rootLogger.Infof("hello %s", "world") 83 require.True(t, scanner.Scan(), "it should print a log statement") 84 require.Equal(t, "2077-01-23T10:15:13.000Z INFO hello world", scanner.Text()) 85 86 rootLogger.Warnf("hello %s", "world") 87 require.True(t, scanner.Scan(), "it should print a log statement") 88 require.Equal(t, "2077-01-23T10:15:13.000Z WARN hello world", scanner.Text()) 89 90 rootLogger.Errorf("hello %s", "world") 91 require.True(t, scanner.Scan(), "it should print a log statement") 92 require.Equal(t, "2077-01-23T10:15:13.000Z ERROR hello world", scanner.Text()) 93 94 rootLogger.Fatalf("hello %s", "world") 95 require.True(t, scanner.Scan(), "it should print a log statement") 96 require.Equal(t, "2077-01-23T10:15:13.000Z ERROR hello world", scanner.Text()) 97 } 98 99 func Test_Printw_All_Levels(t *testing.T) { 100 fileName := t.TempDir() + "out.log" 101 f, err := os.Create(fileName) 102 require.NoError(t, err) 103 defer func() { _ = f.Close() }() 104 105 c := config.New() 106 c.Set("LOG_LEVEL", "EVENT") 107 c.Set("Logger.enableConsole", false) 108 c.Set("Logger.enableFile", true) 109 c.Set("Logger.enableFileNameInLog", false) 110 c.Set("Logger.enableLoggerNameInLog", false) 111 c.Set("Logger.logFileLocation", fileName) 112 loggerFactory := logger.NewFactory(c, constantClockOpt) 113 114 rootLogger := loggerFactory.NewLogger() 115 require.True(t, rootLogger.IsDebugLevel()) 116 117 scanner := bufio.NewScanner(f) 118 119 rootLogger.Debugw("hello world", "key", "value") 120 require.True(t, scanner.Scan(), "it should print a log statement") 121 require.Equal(t, `2077-01-23T10:15:13.000Z DEBUG hello world {"key": "value"}`, scanner.Text()) 122 123 rootLogger.Infow("hello world", "key", "value") 124 require.True(t, scanner.Scan(), "it should print a log statement") 125 require.Equal(t, `2077-01-23T10:15:13.000Z INFO hello world {"key": "value"}`, scanner.Text()) 126 127 rootLogger.Warnw("hello world", "key", "value") 128 require.True(t, scanner.Scan(), "it should print a log statement") 129 require.Equal(t, `2077-01-23T10:15:13.000Z WARN hello world {"key": "value"}`, scanner.Text()) 130 131 rootLogger.Errorw("hello world", "key", "value") 132 require.True(t, scanner.Scan(), "it should print a log statement") 133 require.Equal(t, `2077-01-23T10:15:13.000Z ERROR hello world {"key": "value"}`, scanner.Text()) 134 135 rootLogger.Fatalw("hello world", "key", "value") 136 require.True(t, scanner.Scan(), "it should print a log statement") 137 require.Equal(t, `2077-01-23T10:15:13.000Z ERROR hello world {"key": "value"}`, scanner.Text()) 138 } 139 140 func Test_Logger_With_Context(t *testing.T) { 141 fileName := t.TempDir() + "out.log" 142 f, err := os.Create(fileName) 143 require.NoError(t, err) 144 defer func() { _ = f.Close() }() 145 146 c := config.New() 147 c.Set("LOG_LEVEL", "INFO") 148 c.Set("Logger.enableConsole", false) 149 c.Set("Logger.enableFile", true) 150 c.Set("Logger.enableFileNameInLog", false) 151 c.Set("Logger.enableLoggerNameInLog", false) 152 c.Set("Logger.logFileLocation", fileName) 153 loggerFactory := logger.NewFactory(c, constantClockOpt) 154 rootLogger := loggerFactory.NewLogger() 155 ctxLogger := rootLogger.With("key", "value") 156 157 scanner := bufio.NewScanner(f) 158 159 rootLogger.Info("hello world") 160 require.True(t, scanner.Scan(), "it should print a log statement") 161 require.Equal(t, `2077-01-23T10:15:13.000Z INFO hello world`, scanner.Text()) 162 ctxLogger.Info("hello world") 163 require.True(t, scanner.Scan(), "it should print a log statement") 164 require.Equal(t, `2077-01-23T10:15:13.000Z INFO hello world {"key": "value"}`, scanner.Text()) 165 166 rootLogger.Infof("hello %s", "world") 167 require.True(t, scanner.Scan(), "it should print a log statement") 168 require.Equal(t, `2077-01-23T10:15:13.000Z INFO hello world`, scanner.Text()) 169 ctxLogger.Infof("hello %s", "world") 170 require.True(t, scanner.Scan(), "it should print a log statement") 171 require.Equal(t, `2077-01-23T10:15:13.000Z INFO hello world {"key": "value"}`, scanner.Text()) 172 173 rootLogger.Infow("hello world", "key1", "value1") 174 require.True(t, scanner.Scan(), "it should print a log statement") 175 require.Equal(t, `2077-01-23T10:15:13.000Z INFO hello world {"key1": "value1"}`, scanner.Text()) 176 ctxLogger.Infow("hello world", "key1", "value1") 177 require.True(t, scanner.Scan(), "it should print a log statement") 178 require.Equal(t, `2077-01-23T10:15:13.000Z INFO hello world {"key": "value", "key1": "value1"}`, scanner.Text()) 179 } 180 181 func Test_Logger_Deep_Hierarchy(t *testing.T) { 182 fileName := t.TempDir() + "out.log" 183 f, err := os.Create(fileName) 184 require.NoError(t, err) 185 defer func() { _ = f.Close() }() 186 187 c := config.New() 188 c.Set("LOG_LEVEL", "INFO") 189 c.Set("Logger.enableConsole", false) 190 c.Set("Logger.enableFile", true) 191 c.Set("Logger.enableFileNameInLog", false) 192 c.Set("Logger.logFileLocation", fileName) 193 loggerFactory := logger.NewFactory(c, constantClockOpt) 194 rootLogger := loggerFactory.NewLogger() 195 lvl1Logger := rootLogger.Child("logger1") 196 lvl2Logger := lvl1Logger.Child("logger2") 197 lvl3Logger := lvl2Logger.Child("logger3") 198 199 rootLogger.Info("hello world 0") 200 scanner := bufio.NewScanner(f) 201 require.True(t, scanner.Scan(), "it should print a log statement") 202 require.Equal(t, "2077-01-23T10:15:13.000Z INFO hello world 0", scanner.Text()) 203 204 lvl1Logger.Info("hello world 1") 205 require.True(t, scanner.Scan(), "it should print a log statement") 206 require.Equal(t, "2077-01-23T10:15:13.000Z INFO logger1 hello world 1", scanner.Text()) 207 208 lvl2Logger.Info("hello world 2") 209 require.True(t, scanner.Scan(), "it should print a log statement") 210 require.Equal(t, "2077-01-23T10:15:13.000Z INFO logger1.logger2 hello world 2", scanner.Text()) 211 212 lvl3Logger.Info("hello world 3") 213 require.True(t, scanner.Scan(), "it should print a log statement") 214 require.Equal(t, "2077-01-23T10:15:13.000Z INFO logger1.logger2.logger3 hello world 3", scanner.Text()) 215 } 216 217 func Test_Logger_Json_Output(t *testing.T) { 218 fileName := t.TempDir() + "out.log" 219 f, err := os.Create(fileName) 220 require.NoError(t, err) 221 defer func() { _ = f.Close() }() 222 223 c := config.New() 224 c.Set("LOG_LEVEL", "INFO") 225 c.Set("Logger.enableConsole", false) 226 c.Set("Logger.enableFile", true) 227 c.Set("Logger.enableFileNameInLog", false) 228 c.Set("Logger.logFileLocation", fileName) 229 c.Set("Logger.fileJsonFormat", true) 230 loggerFactory := logger.NewFactory(c, constantClockOpt) 231 rootLogger := loggerFactory.NewLogger().Child("mylogger") 232 ctxLogger := rootLogger.With("key", "value") 233 234 scanner := bufio.NewScanner(f) 235 236 rootLogger.Info("hello world") 237 require.True(t, scanner.Scan(), "it should print a log statement") 238 require.Equal(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world"}`, scanner.Text()) 239 ctxLogger.Info("hello world") 240 require.True(t, scanner.Scan(), "it should print a log statement") 241 require.Equal(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key":"value"}`, scanner.Text()) 242 243 rootLogger.Infof("hello %s", "world") 244 require.True(t, scanner.Scan(), "it should print a log statement") 245 require.Equal(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world"}`, scanner.Text()) 246 ctxLogger.Infof("hello %s", "world") 247 require.True(t, scanner.Scan(), "it should print a log statement") 248 require.Equal(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key":"value"}`, scanner.Text()) 249 250 rootLogger.Infow("hello world", "key1", "value1") 251 require.True(t, scanner.Scan(), "it should print a log statement") 252 require.Equal(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key1":"value1"}`, scanner.Text()) 253 ctxLogger.Infow("hello world", "key1", "value1") 254 require.True(t, scanner.Scan(), "it should print a log statement") 255 require.Equal(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key":"value","key1":"value1"}`, scanner.Text()) 256 } 257 258 func Test_Logger_NonSugared(t *testing.T) { 259 fileName := t.TempDir() + "out.log" 260 f, err := os.Create(fileName) 261 require.NoError(t, err) 262 defer func() { _ = f.Close() }() 263 264 c := config.New() 265 c.Set("LOG_LEVEL", "EVENT") 266 c.Set("Logger.enableConsole", false) 267 c.Set("Logger.enableFile", true) 268 c.Set("Logger.enableFileNameInLog", false) 269 c.Set("Logger.enableStackTrace", false) 270 c.Set("Logger.logFileLocation", fileName) 271 c.Set("Logger.fileJsonFormat", true) 272 loggerFactory := logger.NewFactory(c, constantClockOpt) 273 rootLogger := loggerFactory.NewLogger().Child("mylogger") 274 ctxLogger := rootLogger.Withn(logger.NewBoolField("foo", true)) 275 276 scanner := bufio.NewScanner(f) 277 278 rootLogger.Debugn("hello world", logger.NewStringField("key1", "value1")) 279 require.True(t, scanner.Scan(), "it should print a log statement") 280 require.JSONEq(t, `{"level":"DEBUG","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key1":"value1"}`, scanner.Text()) 281 ctxLogger.Debugn("hello world", logger.NewIntField("key2", 2)) 282 require.True(t, scanner.Scan(), "it should print a log statement") 283 require.JSONEq(t, `{"level":"DEBUG","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key2":2,"foo":true}`, scanner.Text()) 284 285 rootLogger.Infon("hello world", logger.NewStringField("key1", "value1")) 286 require.True(t, scanner.Scan(), "it should print a log statement") 287 require.JSONEq(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key1":"value1"}`, scanner.Text()) 288 ctxLogger.Infon("hello world", logger.NewIntField("key2", 2)) 289 require.True(t, scanner.Scan(), "it should print a log statement") 290 require.JSONEq(t, `{"level":"INFO","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key2":2,"foo":true}`, scanner.Text()) 291 292 rootLogger.Warnn("hello world", logger.NewStringField("key1", "value1")) 293 require.True(t, scanner.Scan(), "it should print a log statement") 294 require.JSONEq(t, `{"level":"WARN","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key1":"value1"}`, scanner.Text()) 295 ctxLogger.Warnn("hello world", logger.NewIntField("key2", 2)) 296 require.True(t, scanner.Scan(), "it should print a log statement") 297 require.JSONEq(t, `{"level":"WARN","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key2":2,"foo":true}`, scanner.Text()) 298 299 rootLogger.Errorn("hello world", logger.NewStringField("key1", "value1")) 300 require.True(t, scanner.Scan(), "it should print a log statement") 301 require.JSONEq(t, `{"level":"ERROR","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key1":"value1"}`, scanner.Text()) 302 ctxLogger.Errorn("hello world", logger.NewIntField("key2", 2)) 303 require.True(t, scanner.Scan(), "it should print a log statement") 304 require.JSONEq(t, `{"level":"ERROR","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key2":2,"foo":true}`, scanner.Text()) 305 306 rootLogger.Fataln("hello world", logger.NewStringField("key1", "value1")) 307 require.True(t, scanner.Scan(), "it should print a log statement") 308 require.JSONEq(t, `{"level":"ERROR","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key1":"value1"}`, scanner.Text()) 309 require.True(t, scanner.Scan(), "it should print a stacktrace statement") 310 require.Contains(t, scanner.Text(), `"level":"ERROR"`) 311 require.Contains(t, scanner.Text(), `"ts":"2077-01-23T10:15:13.000Z"`) 312 require.Contains(t, scanner.Text(), `"logger":"mylogger"`) 313 require.Contains(t, scanner.Text(), `"key1":"value1"`) 314 require.Contains(t, scanner.Text(), `"msg":"goroutine`) 315 316 ctxLogger.Fataln("hello world", logger.NewIntField("key2", 2)) 317 require.True(t, scanner.Scan(), "it should print a log statement") 318 require.JSONEq(t, `{"level":"ERROR","ts":"2077-01-23T10:15:13.000Z","logger":"mylogger","msg":"hello world","key2":2,"foo":true}`, scanner.Text()) 319 require.True(t, scanner.Scan(), "it should print a stacktrace statement") 320 require.Contains(t, scanner.Text(), `"level":"ERROR"`) 321 require.Contains(t, scanner.Text(), `"ts":"2077-01-23T10:15:13.000Z"`) 322 require.Contains(t, scanner.Text(), `"logger":"mylogger"`) 323 require.Contains(t, scanner.Text(), `"key2":2`) 324 require.Contains(t, scanner.Text(), `"foo":true`) 325 require.Contains(t, scanner.Text(), `"msg":"goroutine`) 326 327 rootLogger.Debugn("using all fields", 328 logger.NewField("foo", "any value"), 329 logger.NewStringField("myString", "hello"), 330 logger.NewIntField("myInt", 666), 331 logger.NewBoolField("myBool", true), 332 logger.NewFloatField("myFloat", 1.1), 333 logger.NewTimeField("myTime", time.Date(2077, 1, 23, 10, 15, 13, 0, time.UTC)), 334 logger.NewDurationField("myDuration", time.Second*2+time.Millisecond*321), 335 logger.NewErrorField(errors.New("a bad error")), 336 ) 337 require.True(t, scanner.Scan(), "it should print a log statement") 338 require.JSONEq(t, `{ 339 "level":"DEBUG", 340 "ts":"2077-01-23T10:15:13.000Z", 341 "logger":"mylogger", 342 "msg":"using all fields", 343 "foo":"any value", 344 "myString":"hello", 345 "myInt":666, 346 "myBool":true, 347 "myFloat":1.1, 348 "myTime":"2077-01-23T10:15:13.000Z", 349 "myDuration":2.321, 350 "error":"a bad error" 351 }`, scanner.Text()) 352 } 353 354 func Test_Logger_Expand(t *testing.T) { 355 fileName := t.TempDir() + "out.log" 356 f, err := os.Create(fileName) 357 require.NoError(t, err) 358 defer func() { _ = f.Close() }() 359 360 c := config.New() 361 c.Set("LOG_LEVEL", "EVENT") 362 c.Set("Logger.enableConsole", false) 363 c.Set("Logger.enableFile", true) 364 c.Set("Logger.enableFileNameInLog", false) 365 c.Set("Logger.enableStackTrace", false) 366 c.Set("Logger.logFileLocation", fileName) 367 c.Set("Logger.fileJsonFormat", true) 368 loggerFactory := logger.NewFactory(c, constantClockOpt) 369 rootLogger := loggerFactory.NewLogger().Child("mylogger") 370 371 scanner := bufio.NewScanner(f) 372 373 rootLogger.Debugw("using expand", 374 logger.Expand( 375 logger.NewField("foo", "any value"), 376 logger.NewStringField("myString", "hello"), 377 logger.NewIntField("myInt", 666), 378 logger.NewBoolField("myBool", true), 379 logger.NewFloatField("myFloat", 1.1), 380 logger.NewTimeField("myTime", time.Date(2077, 1, 23, 10, 15, 13, 0, time.UTC)), 381 logger.NewDurationField("myDuration", time.Second*2+time.Millisecond*321), 382 logger.NewErrorField(errors.New("a bad error")), 383 )..., 384 ) 385 require.True(t, scanner.Scan(), "it should print a log statement") 386 require.JSONEq(t, `{ 387 "level":"DEBUG", 388 "ts":"2077-01-23T10:15:13.000Z", 389 "logger":"mylogger", 390 "msg":"using expand", 391 "foo":"any value", 392 "myString":"hello", 393 "myInt":666, 394 "myBool":true, 395 "myFloat":1.1, 396 "myTime":"2077-01-23T10:15:13.000Z", 397 "myDuration":2.321, 398 "error":"a bad error" 399 }`, scanner.Text()) 400 } 401 402 func Test_LogRequest(t *testing.T) { 403 json := `{"key":"value"}` 404 request, err := http.NewRequest(http.MethodPost, "https://example.com", bytes.NewReader([]byte(json))) 405 require.NoError(t, err) 406 c := config.New() 407 c.Set("LOG_LEVEL", "EVENT") 408 c.Set("Logger.enableTimestamp", false) 409 c.Set("Logger.enableFileNameInLog", false) 410 c.Set("Logger.enableLoggerNameInLog", false) 411 stdout := capturer.CaptureStdout(func() { 412 loggerFactory := logger.NewFactory(c, constantClockOpt) 413 l := loggerFactory.NewLogger() 414 l.LogRequest(request) 415 loggerFactory.Sync() 416 }) 417 require.Equal(t, "DEBUG\tRequest Body\t{\"body\": \"{\\\"key\\\":\\\"value\\\"}\"}\n", stdout) 418 } 419 420 type constantClock time.Time 421 422 func (c constantClock) Now() time.Time { return time.Time(c) } 423 func (constantClock) NewTicker(_ time.Duration) *time.Ticker { 424 return &time.Ticker{} 425 } 426 427 var ( 428 date = time.Date(2077, 1, 23, 10, 15, 13, 0o00, time.UTC) 429 constantClockOpt = logger.WithClock(constantClock(date)) 430 )