mirror of
https://github.com/tendermint/tendermint.git
synced 2026-02-03 02:22:04 +00:00
I was digging around in the zero log functions, and the following
functions using the `Fields()` method directly in zerolog,
- https://github.com/rs/zerolog/blob/v1.27.0/event.go#L161
- e9344a8c50/fields.go (L15)
Have meaningfully equivalent semantics and our pre-processing of
values is getting us much (except forcing zerolog to always sort our
keys, and nooping in the case when you miss the last field.)
With this change also, we can pass maps (or, pratically a single map)
to the logger, which might be a less wacky seeming interface.
102 lines
2.6 KiB
Go
102 lines
2.6 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
|
|
}
|