github.com/rudderlabs/rudder-go-kit@v0.30.0/logger/logger.go (about) 1 // Package logger 2 /* 3 Logger Interface Use instance of logger instead of exported functions 4 5 usage example 6 7 import ( 8 "errors" 9 "github.com/rudderlabs/rudder-go-kit/config" 10 "github.com/rudderlabs/rudder-go-kit/logger" 11 ) 12 13 var c = config.New() 14 var loggerFactory = logger.NewFactory(c) 15 var log logger.Logger = loggerFactory.NewLogger() 16 ... 17 log.Error(...) 18 19 or if you want to use the default logger factory (not advised): 20 21 var log logger.Logger = logger.NewLogger() 22 ... 23 log.Error(...) 24 25 */ 26 //go:generate mockgen -destination=mock_logger/mock_logger.go -package mock_logger github.com/rudderlabs/rudder-go-kit/logger Logger 27 package logger 28 29 import ( 30 "bytes" 31 "io" 32 "net/http" 33 "runtime" 34 "strings" 35 36 "go.uber.org/zap" 37 ) 38 39 /* 40 Using levels(like Debug, Info etc.) in logging is a way to categorize logs based on their importance. 41 The idea is to have the option of running the application in different logging levels based on 42 how verbose we want the logging to be. 43 For example, using Debug level of logging, logs everything, and it might slow the application, so we run application 44 in DEBUG level for local development or when we want to look through the entire flow of events in detail. 45 We use 4 logging levels here Debug, Info, Warn and Error. 46 */ 47 48 type Logger interface { 49 // IsDebugLevel Returns true is debug lvl is enabled 50 IsDebugLevel() bool 51 52 // Debug level logging. Most verbose logging level. 53 Debug(args ...any) 54 55 // Debugf does debug level logging similar to fmt.Printf. Most verbose logging level 56 Debugf(format string, args ...any) 57 58 // Debugw does debug level structured logging. Most verbose logging level 59 Debugw(msg string, keysAndValues ...any) 60 61 // Debugn does debug level non-sugared structured logging. Most verbose logging level 62 Debugn(msg string, fields ...Field) 63 64 // Info level logging. Use this to log the state of the application. 65 // Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 66 Info(args ...any) 67 68 // Infof does info level logging similar to fmt.Printf. Use this to log the state of the application. 69 // Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 70 Infof(format string, args ...any) 71 72 // Infow does info level structured logging. Use this to log the state of the application. 73 // Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 74 Infow(msg string, keysAndValues ...any) 75 76 // Infon does info level non-sugared structured logging. Use this to log the state of the application. 77 // Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 78 Infon(msg string, fields ...Field) 79 80 // Warn level logging. Use this to log warnings 81 Warn(args ...any) 82 83 // Warnf does warn level logging similar to fmt.Printf. Use this to log warnings 84 Warnf(format string, args ...any) 85 86 // Warnw does warn level structured logging. Use this to log warnings 87 Warnw(msg string, keysAndValues ...any) 88 89 // Warnn does warn level non-sugared structured logging. Use this to log warnings 90 Warnn(msg string, fields ...Field) 91 92 // Error level logging. Use this to log errors which don't immediately halt the application. 93 Error(args ...any) 94 95 // Errorf does error level logging similar to fmt.Printf. Use this to log errors which don't immediately halt the application. 96 Errorf(format string, args ...any) 97 98 // Errorw does error level structured logging. 99 // Use this to log errors which don't immediately halt the application. 100 Errorw(msg string, keysAndValues ...any) 101 102 // Errorn does error level non-sugared structured logging. 103 // Use this to log errors which don't immediately halt the application. 104 Errorn(msg string, fields ...Field) 105 106 // Fatal level logging. Use this to log errors which crash the application. 107 Fatal(args ...any) 108 109 // Fatalf does fatal level logging similar to fmt.Printf. Use this to log errors which crash the application. 110 Fatalf(format string, args ...any) 111 112 // Fatalw does fatal level structured logging. 113 // Use this to log errors which crash the application. 114 Fatalw(format string, keysAndValues ...any) 115 116 // Fataln does fatal level non-sugared structured logging. 117 // Use this to log errors which crash the application. 118 Fataln(format string, fields ...Field) 119 120 LogRequest(req *http.Request) 121 122 // Child creates a child logger with the given name 123 Child(s string) Logger 124 125 // With adds the provided key value pairs to the logger context 126 With(args ...any) Logger 127 128 // Withn adds the provided key value pairs to the logger context 129 Withn(args ...Field) Logger 130 } 131 132 type logger struct { 133 logConfig *factoryConfig 134 name string 135 zap *zap.Logger 136 sugaredZap *zap.SugaredLogger 137 parent *logger 138 } 139 140 func (l *logger) Child(s string) Logger { 141 if s == "" { 142 return l 143 } 144 cp := *l 145 cp.parent = l 146 if l.name == "" { 147 cp.name = s 148 } else { 149 cp.name = strings.Join([]string{l.name, s}, ".") 150 } 151 if l.logConfig.enableNameInLog { 152 cp.sugaredZap = l.sugaredZap.Named(s) 153 cp.zap = l.zap.Named(s) 154 } 155 return &cp 156 } 157 158 // With adds a variadic number of fields to the logging context. 159 // It accepts a mix of strongly-typed Field objects and loosely-typed key-value pairs. 160 // When processing pairs, the first element of the pair is used as the field key and the second as the field value. 161 func (l *logger) With(args ...any) Logger { 162 cp := *l 163 cp.sugaredZap = cp.sugaredZap.With(args...) 164 for i := 0; i < len(args)-1; i += 2 { 165 key, ok := args[i].(string) 166 if !ok { 167 cp.Warnw("Logger.With called with non-string key", 168 "parentName", l.parent.name, "name", l.name, 169 ) 170 break 171 } 172 cp.zap = cp.zap.With(zap.Any(key, args[i+1])) 173 } 174 return &cp 175 } 176 177 // Withn adds a variadic number of fields to the logging context. 178 // It accepts a mix of strongly-typed Field objects and loosely-typed key-value pairs. 179 // When processing pairs, the first element of the pair is used as the field key and the second as the field value. 180 func (l *logger) Withn(args ...Field) Logger { 181 cp := *l 182 cp.zap = l.zap.With(toZap(args)...) 183 return &cp 184 } 185 186 func (l *logger) getLoggingLevel() int { 187 return l.logConfig.getOrSetLogLevel(l.name, l.parent.getLoggingLevel) 188 } 189 190 // IsDebugLevel Returns true is debug lvl is enabled 191 func (l *logger) IsDebugLevel() bool { 192 return levelDebug >= l.getLoggingLevel() 193 } 194 195 // Debug level logging. 196 // Most verbose logging level. 197 func (l *logger) Debug(args ...any) { 198 if levelDebug >= l.getLoggingLevel() { 199 l.sugaredZap.Debug(args...) 200 } 201 } 202 203 // Info level logging. 204 // Use this to log the state of the application. Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 205 func (l *logger) Info(args ...any) { 206 if levelInfo >= l.getLoggingLevel() { 207 l.sugaredZap.Info(args...) 208 } 209 } 210 211 // Warn level logging. 212 // Use this to log warnings 213 func (l *logger) Warn(args ...any) { 214 if levelWarn >= l.getLoggingLevel() { 215 l.sugaredZap.Warn(args...) 216 } 217 } 218 219 // Error level logging. 220 // Use this to log errors which don't immediately halt the application. 221 func (l *logger) Error(args ...any) { 222 if levelError >= l.getLoggingLevel() { 223 l.sugaredZap.Error(args...) 224 } 225 } 226 227 // Fatal level logging. 228 // Use this to log errors which crash the application. 229 func (l *logger) Fatal(args ...any) { 230 l.sugaredZap.Error(args...) 231 232 // If enableStackTrace is true, Zaplogger will take care of writing stacktrace to the file. 233 // Else, we are force writing the stacktrace to the file. 234 if !l.logConfig.enableStackTrace.Load() { 235 byteArr := make([]byte, 2048) 236 n := runtime.Stack(byteArr, false) 237 stackTrace := string(byteArr[:n]) 238 l.sugaredZap.Error(stackTrace) 239 } 240 _ = l.sugaredZap.Sync() 241 } 242 243 // Debugf does debug level logging similar to fmt.Printf. 244 // Most verbose logging level 245 func (l *logger) Debugf(format string, args ...any) { 246 if levelDebug >= l.getLoggingLevel() { 247 l.sugaredZap.Debugf(format, args...) 248 } 249 } 250 251 // Infof does info level logging similar to fmt.Printf. 252 // Use this to log the state of the application. Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 253 func (l *logger) Infof(format string, args ...any) { 254 if levelInfo >= l.getLoggingLevel() { 255 l.sugaredZap.Infof(format, args...) 256 } 257 } 258 259 // Warnf does warn level logging similar to fmt.Printf. 260 // Use this to log warnings 261 func (l *logger) Warnf(format string, args ...any) { 262 if levelWarn >= l.getLoggingLevel() { 263 l.sugaredZap.Warnf(format, args...) 264 } 265 } 266 267 // Errorf does error level logging similar to fmt.Printf. 268 // Use this to log errors which don't immediately halt the application. 269 func (l *logger) Errorf(format string, args ...any) { 270 if levelError >= l.getLoggingLevel() { 271 l.sugaredZap.Errorf(format, args...) 272 } 273 } 274 275 // Fatalf does fatal level logging similar to fmt.Printf. 276 // Use this to log errors which crash the application. 277 func (l *logger) Fatalf(format string, args ...any) { 278 l.sugaredZap.Errorf(format, args...) 279 280 // If enableStackTrace is true, Zaplogger will take care of writing stacktrace to the file. 281 // Else, we are force writing the stacktrace to the file. 282 if !l.logConfig.enableStackTrace.Load() { 283 byteArr := make([]byte, 2048) 284 n := runtime.Stack(byteArr, false) 285 stackTrace := string(byteArr[:n]) 286 l.sugaredZap.Error(stackTrace) 287 } 288 _ = l.sugaredZap.Sync() 289 } 290 291 // Debugw does debug level structured logging. 292 // Most verbose logging level 293 func (l *logger) Debugw(msg string, keysAndValues ...any) { 294 if levelDebug >= l.getLoggingLevel() { 295 l.sugaredZap.Debugw(msg, keysAndValues...) 296 } 297 } 298 299 // Infow does info level structured logging. 300 // Use this to log the state of the application. Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 301 func (l *logger) Infow(msg string, keysAndValues ...any) { 302 if levelInfo >= l.getLoggingLevel() { 303 l.sugaredZap.Infow(msg, keysAndValues...) 304 } 305 } 306 307 // Warnw does warn level structured logging. 308 // Use this to log warnings 309 func (l *logger) Warnw(msg string, keysAndValues ...any) { 310 if levelWarn >= l.getLoggingLevel() { 311 l.sugaredZap.Warnw(msg, keysAndValues...) 312 } 313 } 314 315 // Errorw does error level structured logging. 316 // Use this to log errors which don't immediately halt the application. 317 func (l *logger) Errorw(msg string, keysAndValues ...any) { 318 if levelError >= l.getLoggingLevel() { 319 l.sugaredZap.Errorw(msg, keysAndValues...) 320 } 321 } 322 323 // Fatalw does fatal level structured logging. 324 // Use this to log errors which crash the application. 325 func (l *logger) Fatalw(msg string, keysAndValues ...any) { 326 l.sugaredZap.Errorw(msg, keysAndValues...) 327 328 // If enableStackTrace is true, Zaplogger will take care of writing stacktrace to the file. 329 // Else, we are force writing the stacktrace to the file. 330 if !l.logConfig.enableStackTrace.Load() { 331 byteArr := make([]byte, 2048) 332 n := runtime.Stack(byteArr, false) 333 stackTrace := string(byteArr[:n]) 334 l.sugaredZap.Error(stackTrace) 335 } 336 _ = l.sugaredZap.Sync() 337 } 338 339 // Debugn does debug level non-sugared structured logging. 340 func (l *logger) Debugn(msg string, fields ...Field) { 341 if levelDebug >= l.getLoggingLevel() { 342 l.zap.Debug(msg, toZap(fields)...) 343 } 344 } 345 346 // Infon does info level non-sugared structured logging. 347 // Use this to log the state of the application. 348 // Don't use Logger.Info in the flow of individual events. Use Logger.Debug instead. 349 func (l *logger) Infon(msg string, fields ...Field) { 350 if levelInfo >= l.getLoggingLevel() { 351 l.zap.Info(msg, toZap(fields)...) 352 } 353 } 354 355 // Warnn does warn level non-sugared structured logging. 356 // Use this to log warnings 357 func (l *logger) Warnn(msg string, fields ...Field) { 358 if levelWarn >= l.getLoggingLevel() { 359 l.zap.Warn(msg, toZap(fields)...) 360 } 361 } 362 363 // Errorn does error level non-sugared structured logging. 364 // Use this to log errors which don't immediately halt the application. 365 func (l *logger) Errorn(msg string, fields ...Field) { 366 if levelError >= l.getLoggingLevel() { 367 l.zap.Error(msg, toZap(fields)...) 368 } 369 } 370 371 // Fataln does fatal level non-sugared structured logging. 372 // Use this to log errors which crash the application. 373 func (l *logger) Fataln(msg string, fields ...Field) { 374 zapFields := toZap(fields) 375 l.zap.Error(msg, zapFields...) 376 377 // If enableStackTrace is true, Zaplogger will take care of writing stacktrace to the file. 378 // Else, we are force writing the stacktrace to the file. 379 if !l.logConfig.enableStackTrace.Load() { 380 byteArr := make([]byte, 2048) 381 n := runtime.Stack(byteArr, false) 382 stackTrace := string(byteArr[:n]) 383 l.zap.Error(stackTrace, zapFields...) 384 } 385 _ = l.zap.Sync() 386 } 387 388 // LogRequest reads and logs the request body and resets the body to original state. 389 func (l *logger) LogRequest(req *http.Request) { 390 if levelEvent >= l.getLoggingLevel() { 391 defer func() { _ = req.Body.Close() }() 392 bodyBytes, _ := io.ReadAll(req.Body) 393 bodyString := string(bodyBytes) 394 req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) 395 // print raw request body for debugging purposes 396 l.zap.Debug("Request Body", zap.String("body", bodyString)) 397 } 398 }