github.com/number571/tendermint@v0.34.11-gost/libs/log/default.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/rs/zerolog"
    11  )
    12  
    13  var _ Logger = (*defaultLogger)(nil)
    14  
    15  type defaultLogger struct {
    16  	zerolog.Logger
    17  
    18  	trace bool
    19  }
    20  
    21  // NewDefaultLogger returns a default logger that can be used within Tendermint
    22  // and that fulfills the Logger interface. The underlying logging provider is a
    23  // zerolog logger that supports typical log levels along with JSON and plain/text
    24  // log formats.
    25  //
    26  // Since zerolog supports typed structured logging and it is difficult to reflect
    27  // that in a generic interface, all logging methods accept a series of key/value
    28  // pair tuples, where the key must be a string.
    29  func NewDefaultLogger(format, level string, trace bool) (Logger, error) {
    30  	var logWriter io.Writer
    31  	switch strings.ToLower(format) {
    32  	case LogFormatPlain, LogFormatText:
    33  		logWriter = zerolog.ConsoleWriter{
    34  			Out:        os.Stderr,
    35  			NoColor:    true,
    36  			TimeFormat: time.RFC3339,
    37  			FormatLevel: func(i interface{}) string {
    38  				if ll, ok := i.(string); ok {
    39  					return strings.ToUpper(ll)
    40  				}
    41  				return "????"
    42  			},
    43  		}
    44  
    45  	case LogFormatJSON:
    46  		logWriter = os.Stderr
    47  
    48  	default:
    49  		return nil, fmt.Errorf("unsupported log format: %s", format)
    50  	}
    51  
    52  	logLevel, err := zerolog.ParseLevel(level)
    53  	if err != nil {
    54  		return nil, fmt.Errorf("failed to parse log level (%s): %w", level, err)
    55  	}
    56  
    57  	// make the writer thread-safe
    58  	logWriter = newSyncWriter(logWriter)
    59  
    60  	return defaultLogger{
    61  		Logger: zerolog.New(logWriter).Level(logLevel).With().Timestamp().Logger(),
    62  		trace:  trace,
    63  	}, nil
    64  }
    65  
    66  // MustNewDefaultLogger delegates a call NewDefaultLogger where it panics on
    67  // error.
    68  func MustNewDefaultLogger(format, level string, trace bool) Logger {
    69  	logger, err := NewDefaultLogger(format, level, trace)
    70  	if err != nil {
    71  		panic(err)
    72  	}
    73  
    74  	return logger
    75  }
    76  
    77  func (l defaultLogger) Info(msg string, keyVals ...interface{}) {
    78  	l.Logger.Info().Fields(getLogFields(keyVals...)).Msg(msg)
    79  }
    80  
    81  func (l defaultLogger) Error(msg string, keyVals ...interface{}) {
    82  	e := l.Logger.Error()
    83  	if l.trace {
    84  		e = e.Stack()
    85  	}
    86  
    87  	e.Fields(getLogFields(keyVals...)).Msg(msg)
    88  }
    89  
    90  func (l defaultLogger) Debug(msg string, keyVals ...interface{}) {
    91  	l.Logger.Debug().Fields(getLogFields(keyVals...)).Msg(msg)
    92  }
    93  
    94  func (l defaultLogger) With(keyVals ...interface{}) Logger {
    95  	return defaultLogger{
    96  		Logger: l.Logger.With().Fields(getLogFields(keyVals...)).Logger(),
    97  		trace:  l.trace,
    98  	}
    99  }
   100  
   101  func getLogFields(keyVals ...interface{}) map[string]interface{} {
   102  	if len(keyVals)%2 != 0 {
   103  		return nil
   104  	}
   105  
   106  	fields := make(map[string]interface{}, len(keyVals))
   107  	for i := 0; i < len(keyVals); i += 2 {
   108  		fields[fmt.Sprint(keyVals[i])] = keyVals[i+1]
   109  	}
   110  
   111  	return fields
   112  }