github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/log/log.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 zkevm "github.com/0xPolygon/supernets2-node" 9 "github.com/hermeznetwork/tracerr" 10 "go.uber.org/zap" 11 "go.uber.org/zap/zapcore" 12 ) 13 14 // LogEnvironment represents the possible log environments. 15 type LogEnvironment string 16 17 const ( 18 // EnvironmentProduction production log environment. 19 EnvironmentProduction = LogEnvironment("production") 20 // EnvironmentDevelopment development log environment. 21 EnvironmentDevelopment = LogEnvironment("development") 22 ) 23 24 // Logger is a wrapper providing logging facilities. 25 type Logger struct { 26 x *zap.SugaredLogger 27 } 28 29 // root logger 30 var log *Logger 31 32 func getDefaultLog() *Logger { 33 if log != nil { 34 return log 35 } 36 // default level: debug 37 zapLogger, _, err := NewLogger(Config{ 38 Environment: EnvironmentDevelopment, 39 Level: "debug", 40 Outputs: []string{"stderr"}, 41 }) 42 if err != nil { 43 panic(err) 44 } 45 log = &Logger{x: zapLogger} 46 return log 47 } 48 49 // Init the logger with defined level. outputs defines the outputs where the 50 // logs will be sent. By default outputs contains "stdout", which prints the 51 // logs at the output of the process. To add a log file as output, the path 52 // should be added at the outputs array. To avoid printing the logs but storing 53 // them on a file, can use []string{"pathtofile.log"} 54 func Init(cfg Config) { 55 zapLogger, _, err := NewLogger(cfg) 56 if err != nil { 57 panic(err) 58 } 59 log = &Logger{x: zapLogger} 60 } 61 62 // NewLogger creates the logger with defined level. outputs defines the outputs where the 63 // logs will be sent. By default, outputs contains "stdout", which prints the 64 // logs at the output of the process. To add a log file as output, the path 65 // should be added at the outputs array. To avoid printing the logs but storing 66 // them on a file, can use []string{"pathtofile.log"} 67 func NewLogger(cfg Config) (*zap.SugaredLogger, *zap.AtomicLevel, error) { 68 var level zap.AtomicLevel 69 err := level.UnmarshalText([]byte(cfg.Level)) 70 if err != nil { 71 return nil, nil, fmt.Errorf("error on setting log level: %s", err) 72 } 73 74 var zapCfg zap.Config 75 76 switch cfg.Environment { 77 case EnvironmentProduction: 78 zapCfg = zap.NewProductionConfig() 79 default: 80 zapCfg = zap.NewDevelopmentConfig() 81 zapCfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder 82 } 83 zapCfg.Level = level 84 zapCfg.OutputPaths = cfg.Outputs 85 zapCfg.InitialFields = map[string]interface{}{ 86 "version": zkevm.Version, 87 "pid": os.Getpid(), 88 } 89 90 logger, err := zapCfg.Build() 91 if err != nil { 92 return nil, nil, err 93 } 94 defer logger.Sync() //nolint:gosec,errcheck 95 96 // skip 2 callers: one for our wrapper methods and one for the package functions 97 withOptions := logger.WithOptions(zap.AddCallerSkip(2)) //nolint:gomnd 98 return withOptions.Sugar(), &level, nil 99 } 100 101 // WithFields returns a new Logger (derived from the root one) with additional 102 // fields as per keyValuePairs. The root Logger instance is not affected. 103 func WithFields(keyValuePairs ...interface{}) *Logger { 104 l := getDefaultLog().WithFields(keyValuePairs...) 105 106 // since we are returning a new instance, remove one caller from the 107 // stack, because we'll be calling the retruned Logger methods 108 // directly, not the package functions. 109 x := l.x.WithOptions(zap.AddCallerSkip(-1)) 110 l.x = x 111 return l 112 } 113 114 // WithFields returns a new Logger with additional fields as per keyValuePairs. 115 // The original Logger instance is not affected. 116 func (l *Logger) WithFields(keyValuePairs ...interface{}) *Logger { 117 return &Logger{ 118 x: l.x.With(keyValuePairs...), 119 } 120 } 121 122 func sprintStackTrace(st []tracerr.Frame) string { 123 builder := strings.Builder{} 124 // Skip deepest frame because it belongs to the go runtime and we don't 125 // care about it. 126 if len(st) > 0 { 127 st = st[:len(st)-1] 128 } 129 for _, f := range st { 130 builder.WriteString(fmt.Sprintf("\n%s:%d %s()", f.Path, f.Line, f.Func)) 131 } 132 builder.WriteString("\n") 133 return builder.String() 134 } 135 136 // appendStackTraceMaybeArgs will append the stacktrace to the args 137 func appendStackTraceMaybeArgs(args []interface{}) []interface{} { 138 for i := range args { 139 if err, ok := args[i].(error); ok { 140 err = tracerr.Wrap(err) 141 st := tracerr.StackTrace(err) 142 return append(args, sprintStackTrace(st)) 143 } 144 } 145 return args 146 } 147 148 // Debug calls log.Debug 149 func (l *Logger) Debug(args ...interface{}) { 150 l.x.Debug(args...) 151 } 152 153 // Info calls log.Info 154 func (l *Logger) Info(args ...interface{}) { 155 l.x.Info(args...) 156 } 157 158 // Warn calls log.Warn 159 func (l *Logger) Warn(args ...interface{}) { 160 l.x.Warn(args...) 161 } 162 163 // Error calls log.Error 164 func (l *Logger) Error(args ...interface{}) { 165 l.x.Error(args...) 166 } 167 168 // Fatal calls log.Fatal 169 func (l *Logger) Fatal(args ...interface{}) { 170 l.x.Fatal(args...) 171 } 172 173 // Debugf calls log.Debugf 174 func (l *Logger) Debugf(template string, args ...interface{}) { 175 l.x.Debugf(template, args...) 176 } 177 178 // Infof calls log.Infof 179 func (l *Logger) Infof(template string, args ...interface{}) { 180 l.x.Infof(template, args...) 181 } 182 183 // Warnf calls log.Warnf 184 func (l *Logger) Warnf(template string, args ...interface{}) { 185 l.x.Warnf(template, args...) 186 } 187 188 // Fatalf calls log.Fatalf 189 func (l *Logger) Fatalf(template string, args ...interface{}) { 190 l.x.Fatalf(template, args...) 191 } 192 193 // Errorf calls log.Errorf and stores the error message into the ErrorFile 194 func (l *Logger) Errorf(template string, args ...interface{}) { 195 l.x.Errorf(template, args...) 196 } 197 198 // Debug calls log.Debug on the root Logger. 199 func Debug(args ...interface{}) { 200 getDefaultLog().Debug(args...) 201 } 202 203 // Info calls log.Info on the root Logger. 204 func Info(args ...interface{}) { 205 getDefaultLog().Info(args...) 206 } 207 208 // Warn calls log.Warn on the root Logger. 209 func Warn(args ...interface{}) { 210 getDefaultLog().Warn(args...) 211 } 212 213 // Error calls log.Error on the root Logger. 214 func Error(args ...interface{}) { 215 args = appendStackTraceMaybeArgs(args) 216 getDefaultLog().Error(args...) 217 } 218 219 // Fatal calls log.Fatal on the root Logger. 220 func Fatal(args ...interface{}) { 221 args = appendStackTraceMaybeArgs(args) 222 getDefaultLog().Fatal(args...) 223 } 224 225 // Debugf calls log.Debugf on the root Logger. 226 func Debugf(template string, args ...interface{}) { 227 getDefaultLog().Debugf(template, args...) 228 } 229 230 // Infof calls log.Infof on the root Logger. 231 func Infof(template string, args ...interface{}) { 232 getDefaultLog().Infof(template, args...) 233 } 234 235 // Warnf calls log.Warnf on the root Logger. 236 func Warnf(template string, args ...interface{}) { 237 getDefaultLog().Warnf(template, args...) 238 } 239 240 // Fatalf calls log.Fatalf on the root Logger. 241 func Fatalf(template string, args ...interface{}) { 242 args = appendStackTraceMaybeArgs(args) 243 getDefaultLog().Fatalf(template+" %s", args...) 244 } 245 246 // Errorf calls log.Errorf on the root logger and stores the error message into 247 // the ErrorFile. 248 func Errorf(template string, args ...interface{}) { 249 args = appendStackTraceMaybeArgs(args) 250 getDefaultLog().Errorf(template+" %s", args...) 251 } 252 253 // appendStackTraceMaybeKV will append the stacktrace to the KV 254 func appendStackTraceMaybeKV(msg string, kv []interface{}) string { 255 for i := range kv { 256 if i%2 == 0 { 257 continue 258 } 259 if err, ok := kv[i].(error); ok { 260 err = tracerr.Wrap(err) 261 st := tracerr.StackTrace(err) 262 return fmt.Sprintf("%v: %v%v\n", msg, err, sprintStackTrace(st)) 263 } 264 } 265 return msg 266 } 267 268 // Debugw calls log.Debugw 269 func (l *Logger) Debugw(msg string, kv ...interface{}) { 270 l.x.Debugw(msg, kv...) 271 } 272 273 // Infow calls log.Infow 274 func (l *Logger) Infow(msg string, kv ...interface{}) { 275 l.x.Infow(msg, kv...) 276 } 277 278 // Warnw calls log.Warnw 279 func (l *Logger) Warnw(msg string, kv ...interface{}) { 280 l.x.Warnw(msg, kv...) 281 } 282 283 // Errorw calls log.Errorw 284 func (l *Logger) Errorw(msg string, kv ...interface{}) { 285 l.x.Errorw(msg, kv...) 286 } 287 288 // Fatalw calls log.Fatalw 289 func (l *Logger) Fatalw(msg string, kv ...interface{}) { 290 l.x.Fatalw(msg, kv...) 291 } 292 293 // Debugw calls log.Debugw on the root Logger. 294 func Debugw(msg string, kv ...interface{}) { 295 getDefaultLog().Debugw(msg, kv...) 296 } 297 298 // Infow calls log.Infow on the root Logger. 299 func Infow(msg string, kv ...interface{}) { 300 getDefaultLog().Infow(msg, kv...) 301 } 302 303 // Warnw calls log.Warnw on the root Logger. 304 func Warnw(msg string, kv ...interface{}) { 305 getDefaultLog().Warnw(msg, kv...) 306 } 307 308 // Errorw calls log.Errorw on the root Logger. 309 func Errorw(msg string, kv ...interface{}) { 310 msg = appendStackTraceMaybeKV(msg, kv) 311 getDefaultLog().Errorw(msg, kv...) 312 } 313 314 // Fatalw calls log.Fatalw on the root Logger. 315 func Fatalw(msg string, kv ...interface{}) { 316 msg = appendStackTraceMaybeKV(msg, kv) 317 getDefaultLog().Fatalw(msg, kv...) 318 }