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  }