github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/libs/log/zerolog_logger.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/rs/zerolog"
     8  	"gopkg.in/natefinch/lumberjack.v2"
     9  )
    10  
    11  var _ Logger = (*ZeroLogWrapper)(nil)
    12  
    13  // ZeroLogWrapper provides a wrapper around a zerolog.Logger instance. It implements
    14  // Tendermint's Logger interface.
    15  type ZeroLogWrapper struct {
    16  	zerolog.Logger
    17  }
    18  
    19  type ZeroLogConfig struct {
    20  	IsLogPlain bool
    21  	LogLevel   string
    22  
    23  	LogPath       string
    24  	LogMaxAge     int
    25  	LogMaxSize    int
    26  	LogMaxBackups int
    27  }
    28  
    29  func NewZeroLogConfig(isLogPlain bool, logLevel string, logPath string, logMaxAge int, logMaxSize int, logMaxBackups int) ZeroLogConfig {
    30  	return ZeroLogConfig{
    31  		IsLogPlain:    isLogPlain,
    32  		LogLevel:      logLevel,
    33  		LogPath:       logPath,
    34  		LogMaxAge:     logMaxAge,
    35  		LogMaxSize:    logMaxSize,
    36  		LogMaxBackups: logMaxBackups,
    37  	}
    38  }
    39  
    40  func NewZeroLogLogger(cfg ZeroLogConfig, consoleWriter io.Writer) (Logger, error) {
    41  	var logWriter io.Writer
    42  	if cfg.IsLogPlain {
    43  		logWriter = zerolog.ConsoleWriter{
    44  			Out:        consoleWriter,
    45  			TimeFormat: "2006/01/02-15:04:05.999",
    46  		}
    47  	} else {
    48  		logWriter = consoleWriter
    49  	}
    50  
    51  	var zeroLogLogger zerolog.Logger
    52  	if cfg.LogPath != "" {
    53  		// initialize the rotator
    54  		rotator := &lumberjack.Logger{
    55  			Filename:   cfg.LogPath,
    56  			MaxAge:     cfg.LogMaxAge,
    57  			MaxSize:    cfg.LogMaxSize,
    58  			MaxBackups: cfg.LogMaxBackups,
    59  		}
    60  
    61  		// set log format
    62  		var fileLogWriter io.Writer
    63  		if cfg.IsLogPlain {
    64  			fileLogWriter = zerolog.ConsoleWriter{
    65  				Out:        rotator,
    66  				NoColor:    true,
    67  				TimeFormat: "2006/01/02-15:04:05.999",
    68  			}
    69  		} else {
    70  			fileLogWriter = rotator
    71  		}
    72  
    73  		zeroLogLogger = zerolog.New(zerolog.MultiLevelWriter(logWriter, fileLogWriter)).With().Timestamp().Logger()
    74  	} else {
    75  		zeroLogLogger = zerolog.New(logWriter).With().Timestamp().Logger()
    76  	}
    77  
    78  	leveledZeroLogLogger, err := ParseLogLevel(cfg.LogLevel, ZeroLogWrapper{zeroLogLogger}, "info")
    79  	if err != nil {
    80  		return nil, fmt.Errorf("failed to parse log level (%s): %w", cfg.LogLevel, err)
    81  	}
    82  
    83  	return leveledZeroLogLogger, nil
    84  }
    85  
    86  func init() {
    87  	zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
    88  }
    89  
    90  // Info implements Tendermint's Logger interface and logs with level INFO. A set
    91  // of key/value tuples may be provided to add context to the log. The number of
    92  // tuples must be even and the key of the tuple must be a string.
    93  func (z ZeroLogWrapper) Info(msg string, keyVals ...interface{}) {
    94  	z.Logger.Info().Fields(getLogFields(keyVals...)).Msg(msg)
    95  }
    96  
    97  // Error implements Tendermint's Logger interface and logs with level ERR. A set
    98  // of key/value tuples may be provided to add context to the log. The number of
    99  // tuples must be even and the key of the tuple must be a string.
   100  func (z ZeroLogWrapper) Error(msg string, keyVals ...interface{}) {
   101  	z.Logger.Error().Fields(getLogFields(keyVals...)).Msg(msg)
   102  }
   103  
   104  // Debug implements Tendermint's Logger interface and logs with level DEBUG. A set
   105  // of key/value tuples may be provided to add context to the log. The number of
   106  // tuples must be even and the key of the tuple must be a string.
   107  func (z ZeroLogWrapper) Debug(msg string, keyVals ...interface{}) {
   108  	z.Logger.Debug().Fields(getLogFields(keyVals...)).Msg(msg)
   109  }
   110  
   111  // With returns a new wrapped logger with additional context provided by a set
   112  // of key/value tuples. The number of tuples must be even and the key of the
   113  // tuple must be a string.
   114  func (z ZeroLogWrapper) With(keyVals ...interface{}) Logger {
   115  	return ZeroLogWrapper{z.Logger.With().Fields(getLogFields(keyVals...)).Logger()}
   116  }
   117  
   118  func getLogFields(keyVals ...interface{}) map[string]interface{} {
   119  	if len(keyVals)%2 != 0 {
   120  		return nil
   121  	}
   122  
   123  	fields := make(map[string]interface{})
   124  	for i := 0; i < len(keyVals); i += 2 {
   125  		fields[keyVals[i].(string)] = keyVals[i+1]
   126  	}
   127  
   128  	return fields
   129  }