github.com/leovct/zkevm-bridge-service@v0.4.4/log/log.go (about)

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