You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

125 lines
3.1 KiB

package log
import (
"fmt"
"io"
"os"
"strings"
"time"
"github.com/rs/zerolog"
)
var _ Logger = (*defaultLogger)(nil)
type defaultLogger struct {
zerolog.Logger
}
// NewDefaultLogger returns a default logger that can be used within Tendermint
// and that fulfills the Logger interface. The underlying logging provider is a
// zerolog logger that supports typical log levels along with JSON and plain/text
// log formats.
//
// Since zerolog supports typed structured logging and it is difficult to reflect
// that in a generic interface, all logging methods accept a series of key/value
// pair tuples, where the key must be a string.
func NewDefaultLogger(format, level string) (Logger, error) {
var logWriter io.Writer
switch strings.ToLower(format) {
case LogFormatPlain, LogFormatText:
logWriter = zerolog.ConsoleWriter{
Out: os.Stderr,
NoColor: true,
TimeFormat: time.RFC3339,
FormatLevel: func(i interface{}) string {
if ll, ok := i.(string); ok {
return strings.ToUpper(ll)
}
return "????"
},
}
case LogFormatJSON:
logWriter = os.Stderr
default:
return nil, fmt.Errorf("unsupported log format: %s", format)
}
logLevel, err := zerolog.ParseLevel(level)
if err != nil {
return nil, fmt.Errorf("failed to parse log level (%s): %w", level, err)
}
// make the writer thread-safe
logWriter = newSyncWriter(logWriter)
return &defaultLogger{
Logger: zerolog.New(logWriter).Level(logLevel).With().Timestamp().Logger(),
}, nil
}
// MustNewDefaultLogger delegates a call NewDefaultLogger where it panics on
// error.
func MustNewDefaultLogger(format, level string) Logger {
logger, err := NewDefaultLogger(format, level)
if err != nil {
panic(err)
}
return logger
}
func (l defaultLogger) Info(msg string, keyVals ...interface{}) {
l.Logger.Info().Fields(getLogFields(keyVals...)).Msg(msg)
}
func (l defaultLogger) Error(msg string, keyVals ...interface{}) {
l.Logger.Error().Fields(getLogFields(keyVals...)).Msg(msg)
}
func (l defaultLogger) Debug(msg string, keyVals ...interface{}) {
l.Logger.Debug().Fields(getLogFields(keyVals...)).Msg(msg)
}
func (l defaultLogger) With(keyVals ...interface{}) Logger {
return &defaultLogger{
Logger: l.Logger.With().Fields(getLogFields(keyVals...)).Logger(),
}
}
// OverrideWithNewLogger replaces an existing logger's internal with
// a new logger, and makes it possible to reconfigure an existing
// logger that has already been propagated to callers.
func OverrideWithNewLogger(logger Logger, format, level string) error {
ol, ok := logger.(*defaultLogger)
if !ok {
return fmt.Errorf("logger %T cannot be overridden", logger)
}
newLogger, err := NewDefaultLogger(format, level)
if err != nil {
return err
}
nl, ok := newLogger.(*defaultLogger)
if !ok {
return fmt.Errorf("logger %T cannot be overridden by %T", logger, newLogger)
}
ol.Logger = nl.Logger
return nil
}
func getLogFields(keyVals ...interface{}) map[string]interface{} {
if len(keyVals)%2 != 0 {
return nil
}
fields := make(map[string]interface{}, len(keyVals))
for i := 0; i < len(keyVals); i += 2 {
fields[fmt.Sprint(keyVals[i])] = keyVals[i+1]
}
return fields
}