mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-08 14:21:14 +00:00
shout out to @joeabbey for the inspiration. This makes the lazy functions internal by default to prevent potential misuse by external callers. Should backport cleanly into 0.36 and I'll handle a messy merge into 0.35
98 lines
2.5 KiB
Go
98 lines
2.5 KiB
Go
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
|
|
}
|
|
|
|
func (l defaultLogger) Info(msg string, keyVals ...interface{}) {
|
|
l.Logger.Info().Fields(keyVals).Msg(msg)
|
|
}
|
|
|
|
func (l defaultLogger) Error(msg string, keyVals ...interface{}) {
|
|
l.Logger.Error().Fields(keyVals).Msg(msg)
|
|
}
|
|
|
|
func (l defaultLogger) Debug(msg string, keyVals ...interface{}) {
|
|
l.Logger.Debug().Fields(keyVals).Msg(msg)
|
|
}
|
|
|
|
func (l defaultLogger) With(keyVals ...interface{}) Logger {
|
|
return &defaultLogger{Logger: l.Logger.With().Fields(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
|
|
}
|