loggers updated to match to interface (#480)
refactor loggers to match go-micro changes
This commit is contained in:
parent
cf98ce105a
commit
bf669d8b9e
58
options.go
58
options.go
@ -1,82 +1,66 @@
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
logger.Options
|
||||
|
||||
// Flag for whether to log caller info (off by default)
|
||||
ReportCaller bool
|
||||
// Use this logger as system wide default logger (off by default)
|
||||
UseAsDefault bool
|
||||
// zerolog hooks
|
||||
Hooks []zerolog.Hook
|
||||
// TimeFormat is one of time.RFC3339, time.RFC3339Nano, time.*
|
||||
TimeFormat string
|
||||
// Runtime mode. (Production by default)
|
||||
Mode Mode
|
||||
// Exit Function to call when FatalLevel log
|
||||
ExitFunc func(int)
|
||||
}
|
||||
|
||||
type reportCallerKey struct{}
|
||||
|
||||
func ReportCaller() logger.Option {
|
||||
return setOption(reportCallerKey{}, true)
|
||||
return logger.SetOption(reportCallerKey{}, true)
|
||||
}
|
||||
|
||||
type useAsDefaultKey struct{}
|
||||
|
||||
func UseAsDefault() logger.Option {
|
||||
return setOption(useAsDefaultKey{}, true)
|
||||
return logger.SetOption(useAsDefaultKey{}, true)
|
||||
}
|
||||
|
||||
type developmentModeKey struct{}
|
||||
|
||||
func WithDevelopmentMode() logger.Option {
|
||||
return setOption(developmentModeKey{}, true)
|
||||
return logger.SetOption(developmentModeKey{}, true)
|
||||
}
|
||||
|
||||
type productionModeKey struct{}
|
||||
|
||||
func WithProductionMode() logger.Option {
|
||||
return setOption(productionModeKey{}, true)
|
||||
}
|
||||
|
||||
type outKey struct{}
|
||||
|
||||
func WithOut(out io.Writer) logger.Option {
|
||||
return setOption(outKey{}, out)
|
||||
}
|
||||
|
||||
type fieldsKey struct{}
|
||||
|
||||
func WithFields(fields map[string]interface{}) logger.Option {
|
||||
return setOption(fieldsKey{}, fields)
|
||||
}
|
||||
|
||||
type levelKey struct{}
|
||||
|
||||
func WithLevel(lvl logger.Level) logger.Option {
|
||||
return setOption(levelKey{}, lvl)
|
||||
return logger.SetOption(productionModeKey{}, true)
|
||||
}
|
||||
|
||||
type timeFormatKey struct{}
|
||||
|
||||
func WithTimeFormat(timeFormat string) logger.Option {
|
||||
return setOption(timeFormatKey{}, timeFormat)
|
||||
return logger.SetOption(timeFormatKey{}, timeFormat)
|
||||
}
|
||||
|
||||
type hooksKey struct{}
|
||||
|
||||
func WithHooks(hooks []zerolog.Hook) logger.Option {
|
||||
return setOption(hooksKey{}, hooks)
|
||||
return logger.SetOption(hooksKey{}, hooks)
|
||||
}
|
||||
|
||||
type exitKey struct{}
|
||||
|
||||
func WithExitFunc(exit func(int)) logger.Option {
|
||||
return setOption(exitKey{}, exit)
|
||||
}
|
||||
|
||||
func setOption(k, v interface{}) logger.Option {
|
||||
return func(o *logger.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
return logger.SetOption(exitKey{}, exit)
|
||||
}
|
||||
|
183
zerolog.go
183
zerolog.go
@ -3,95 +3,61 @@ package zerolog
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/rs/zerolog"
|
||||
zlog "github.com/rs/zerolog/log"
|
||||
"github.com/rs/zerolog/pkgerrors"
|
||||
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type Mode uint8
|
||||
|
||||
const (
|
||||
Production Mode = iota + 1
|
||||
Production Mode = iota
|
||||
Development
|
||||
)
|
||||
|
||||
var (
|
||||
// It's common to set this to a file, or leave it default which is `os.Stderr`
|
||||
out io.Writer = os.Stderr
|
||||
// Function to exit the application, defaults to `os.Exit()`
|
||||
exitFunc = os.Exit
|
||||
// Flag for whether to log caller info (off by default)
|
||||
reportCaller = false
|
||||
// use this logger as system wide default logger
|
||||
useAsDefault = false
|
||||
// The logging level the logger should log at.
|
||||
// This defaults to 100 means not explicitly set by user
|
||||
level logger.Level = 100
|
||||
fields map[string]interface{}
|
||||
hooks []zerolog.Hook
|
||||
timeFormat string
|
||||
// default Production (1)
|
||||
mode Mode = Production
|
||||
)
|
||||
|
||||
type zeroLogger struct {
|
||||
nativelogger zerolog.Logger
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Fields(fields map[string]interface{}) logger.Logger {
|
||||
return &zeroLogger{l.nativelogger.With().Fields(fields).Logger()}
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Error(err error) logger.Logger {
|
||||
return &zeroLogger{
|
||||
l.nativelogger.With().Fields(map[string]interface{}{zerolog.ErrorFieldName: err}).Logger(),
|
||||
}
|
||||
zLog zerolog.Logger
|
||||
opts Options
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Init(opts ...logger.Option) error {
|
||||
|
||||
options := &Options{logger.Options{Context: context.Background()}}
|
||||
for _, o := range opts {
|
||||
o(&options.Options)
|
||||
o(&l.opts.Options)
|
||||
}
|
||||
|
||||
if o, ok := options.Context.Value(outKey{}).(io.Writer); ok {
|
||||
out = o
|
||||
if hs, ok := l.opts.Context.Value(hooksKey{}).([]zerolog.Hook); ok {
|
||||
l.opts.Hooks = hs
|
||||
}
|
||||
if hs, ok := options.Context.Value(hooksKey{}).([]zerolog.Hook); ok {
|
||||
hooks = hs
|
||||
if tf, ok := l.opts.Context.Value(timeFormatKey{}).(string); ok {
|
||||
l.opts.TimeFormat = tf
|
||||
}
|
||||
if flds, ok := options.Context.Value(fieldsKey{}).(map[string]interface{}); ok {
|
||||
fields = flds
|
||||
if exitFunction, ok := l.opts.Context.Value(exitKey{}).(func(int)); ok {
|
||||
l.opts.ExitFunc = exitFunction
|
||||
}
|
||||
if lvl, ok := options.Context.Value(levelKey{}).(logger.Level); ok {
|
||||
level = lvl
|
||||
if caller, ok := l.opts.Context.Value(reportCallerKey{}).(bool); ok && caller {
|
||||
l.opts.ReportCaller = caller
|
||||
}
|
||||
if tf, ok := options.Context.Value(timeFormatKey{}).(string); ok {
|
||||
timeFormat = tf
|
||||
if useDefault, ok := l.opts.Context.Value(useAsDefaultKey{}).(bool); ok && useDefault {
|
||||
l.opts.UseAsDefault = useDefault
|
||||
}
|
||||
if exitFunction, ok := options.Context.Value(exitKey{}).(func(int)); ok {
|
||||
exitFunc = exitFunction
|
||||
if devMode, ok := l.opts.Context.Value(developmentModeKey{}).(bool); ok && devMode {
|
||||
l.opts.Mode = Development
|
||||
}
|
||||
if caller, ok := options.Context.Value(reportCallerKey{}).(bool); ok && caller {
|
||||
reportCaller = caller
|
||||
}
|
||||
if useDefault, ok := options.Context.Value(useAsDefaultKey{}).(bool); ok && useDefault {
|
||||
useAsDefault = useDefault
|
||||
}
|
||||
if devMode, ok := options.Context.Value(developmentModeKey{}).(bool); ok && devMode {
|
||||
mode = Development
|
||||
}
|
||||
if prodMode, ok := options.Context.Value(productionModeKey{}).(bool); ok && prodMode {
|
||||
mode = Production
|
||||
if prodMode, ok := l.opts.Context.Value(productionModeKey{}).(bool); ok && prodMode {
|
||||
l.opts.Mode = Production
|
||||
}
|
||||
|
||||
switch mode {
|
||||
// RESET
|
||||
zerolog.TimeFieldFormat = time.RFC3339
|
||||
zerolog.ErrorStackMarshaler = nil
|
||||
|
||||
switch l.opts.Mode {
|
||||
case Development:
|
||||
zerolog.ErrorStackMarshaler = func(err error) interface{} {
|
||||
fmt.Println(string(debug.Stack()))
|
||||
@ -99,84 +65,80 @@ func (l *zeroLogger) Init(opts ...logger.Option) error {
|
||||
}
|
||||
consOut := zerolog.NewConsoleWriter(
|
||||
func(w *zerolog.ConsoleWriter) {
|
||||
if len(timeFormat) > 0 {
|
||||
w.TimeFormat = timeFormat
|
||||
if len(l.opts.TimeFormat) > 0 {
|
||||
w.TimeFormat = l.opts.TimeFormat
|
||||
}
|
||||
w.Out = out
|
||||
w.Out = l.opts.Out
|
||||
w.NoColor = false
|
||||
},
|
||||
)
|
||||
level = logger.DebugLevel
|
||||
l.nativelogger = zerolog.New(consOut).
|
||||
//level = logger.DebugLevel
|
||||
l.zLog = zerolog.New(consOut).
|
||||
Level(zerolog.DebugLevel).
|
||||
With().Timestamp().Stack().Logger()
|
||||
default: // Production
|
||||
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
||||
l.nativelogger = zerolog.New(out).
|
||||
l.zLog = zerolog.New(l.opts.Out).
|
||||
Level(zerolog.InfoLevel).
|
||||
With().Timestamp().Stack().Logger()
|
||||
}
|
||||
|
||||
// Change Writer if not default
|
||||
if out != os.Stderr {
|
||||
l.nativelogger = l.nativelogger.Output(out)
|
||||
}
|
||||
|
||||
// Set log Level if not default
|
||||
if level != 100 {
|
||||
//zerolog.SetGlobalLevel(loggerToZerologLevel(level))
|
||||
l.nativelogger = l.nativelogger.Level(loggerToZerologLevel(level))
|
||||
if l.opts.Level != 100 {
|
||||
zerolog.SetGlobalLevel(loggerToZerologLevel(l.opts.Level))
|
||||
l.zLog = l.zLog.Level(loggerToZerologLevel(l.opts.Level))
|
||||
}
|
||||
|
||||
// Adding hooks if exist
|
||||
if reportCaller {
|
||||
l.nativelogger = l.nativelogger.With().Caller().Logger()
|
||||
if l.opts.ReportCaller {
|
||||
l.zLog = l.zLog.With().Caller().Logger()
|
||||
}
|
||||
for _, hook := range hooks {
|
||||
l.nativelogger = l.nativelogger.Hook(hook)
|
||||
for _, hook := range l.opts.Hooks {
|
||||
l.zLog = l.zLog.Hook(hook)
|
||||
}
|
||||
|
||||
// Setting timeFormat
|
||||
if len(timeFormat) > 0 {
|
||||
zerolog.TimeFieldFormat = timeFormat
|
||||
if len(l.opts.TimeFormat) > 0 {
|
||||
zerolog.TimeFieldFormat = l.opts.TimeFormat
|
||||
}
|
||||
|
||||
// Adding seed fields if exist
|
||||
if fields != nil {
|
||||
l.nativelogger = l.nativelogger.With().Fields(fields).Logger()
|
||||
if l.opts.Fields != nil {
|
||||
l.zLog = l.zLog.With().Fields(l.opts.Fields).Logger()
|
||||
}
|
||||
|
||||
// Also set it as zerolog's Default logger
|
||||
if useAsDefault {
|
||||
zlog.Logger = l.nativelogger
|
||||
if l.opts.UseAsDefault {
|
||||
zlog.Logger = l.zLog
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *zeroLogger) SetLevel(level logger.Level) {
|
||||
//zerolog.SetGlobalLevel(loggerToZerologLevel(level))
|
||||
l.nativelogger = l.nativelogger.Level(loggerToZerologLevel(level))
|
||||
func (l *zeroLogger) Fields(fields map[string]interface{}) logger.Logger {
|
||||
l.zLog = l.zLog.With().Fields(fields).Logger()
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Level() logger.Level {
|
||||
return ZerologToLoggerLevel(l.nativelogger.GetLevel())
|
||||
func (l *zeroLogger) Error(err error) logger.Logger {
|
||||
l.zLog = l.zLog.With().Fields(map[string]interface{}{zerolog.ErrorFieldName: err}).Logger()
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Log(level logger.Level, args ...interface{}) {
|
||||
msg := fmt.Sprintf("%s", args)
|
||||
l.nativelogger.WithLevel(loggerToZerologLevel(level)).Msg(msg[1 : len(msg)-1])
|
||||
msg := fmt.Sprint(args...)
|
||||
l.zLog.WithLevel(loggerToZerologLevel(level)).Msg(msg)
|
||||
// Invoke os.Exit because unlike zerolog.Logger.Fatal zerolog.Logger.WithLevel won't stop the execution.
|
||||
if level == logger.FatalLevel {
|
||||
exitFunc(1)
|
||||
l.opts.ExitFunc(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Logf(level logger.Level, format string, args ...interface{}) {
|
||||
l.nativelogger.WithLevel(loggerToZerologLevel(level)).Msgf(format, args...)
|
||||
l.zLog.WithLevel(loggerToZerologLevel(level)).Msgf(format, args...)
|
||||
// Invoke os.Exit because unlike zerolog.Logger.Fatal zerolog.Logger.WithLevel won't stop the execution.
|
||||
if level == logger.FatalLevel {
|
||||
exitFunc(1)
|
||||
l.opts.ExitFunc(1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,21 +146,30 @@ func (l *zeroLogger) String() string {
|
||||
return "zerolog"
|
||||
}
|
||||
|
||||
// NewLogger builds a new logger based on options
|
||||
func NewLogger(opts ...logger.Option) logger.Logger {
|
||||
l := &zeroLogger{}
|
||||
_ = l.Init(opts...)
|
||||
return l
|
||||
func (l *zeroLogger) Options() logger.Options {
|
||||
// FIXME: How to return full opts?
|
||||
return l.opts.Options
|
||||
}
|
||||
|
||||
// ParseLevel converts a level string into a logger Level value.
|
||||
// returns an error if the input string does not match known values.
|
||||
func ParseLevel(levelStr string) (lvl logger.Level, err error) {
|
||||
if zLevel, err := zerolog.ParseLevel(levelStr); err == nil {
|
||||
return ZerologToLoggerLevel(zLevel), err
|
||||
} else {
|
||||
return lvl, fmt.Errorf("Unknown Level String: '%s' %w", levelStr, err)
|
||||
// NewLogger builds a new logger based on options
|
||||
func NewLogger(opts ...logger.Option) logger.Logger {
|
||||
// Default options
|
||||
options := Options{
|
||||
Options: logger.Options{
|
||||
Level: 100,
|
||||
Fields: make(map[string]interface{}),
|
||||
Out: os.Stderr,
|
||||
Context: context.Background(),
|
||||
},
|
||||
ReportCaller: false,
|
||||
UseAsDefault: false,
|
||||
Mode: Production,
|
||||
ExitFunc: os.Exit,
|
||||
}
|
||||
|
||||
l := &zeroLogger{opts: options}
|
||||
_ = l.Init(opts...)
|
||||
return l
|
||||
}
|
||||
|
||||
func loggerToZerologLevel(level logger.Level) zerolog.Level {
|
||||
|
@ -20,47 +20,44 @@ func TestName(t *testing.T) {
|
||||
t.Logf("testing logger name: %s", l.String())
|
||||
}
|
||||
|
||||
// func ExampleWithOut() {
|
||||
// l := NewLogger(WithOut(os.Stdout), WithProductionMode())
|
||||
func TestWithOutput(t *testing.T) {
|
||||
logger.DefaultLogger = NewLogger(logger.WithOutput(os.Stdout))
|
||||
|
||||
// l.Logf(logger.InfoLevel, "testing: %s", "logf")
|
||||
|
||||
// // Output:
|
||||
// // {"level":"info","time":"2020-02-14T22:15:36-08:00","message":"testing: logf"}
|
||||
// }
|
||||
logger.Logf(logger.InfoLevel, "testing: %s", "WithOutput")
|
||||
}
|
||||
|
||||
func TestSetLevel(t *testing.T) {
|
||||
l := NewLogger()
|
||||
logger.DefaultLogger = NewLogger()
|
||||
|
||||
l.SetLevel(logger.DebugLevel)
|
||||
l.Logf(logger.DebugLevel, "test show debug: %s", "debug msg")
|
||||
logger.Init(logger.WithLevel(logger.DebugLevel))
|
||||
logger.Logf(logger.DebugLevel, "test show debug: %s", "debug msg")
|
||||
|
||||
l.SetLevel(logger.InfoLevel)
|
||||
l.Logf(logger.DebugLevel, "test non-show debug: %s", "debug msg")
|
||||
logger.Init(logger.WithLevel(logger.InfoLevel))
|
||||
logger.Logf(logger.DebugLevel, "test non-show debug: %s", "debug msg")
|
||||
}
|
||||
|
||||
func TestWithReportCaller(t *testing.T) {
|
||||
l := NewLogger(ReportCaller())
|
||||
logger.DefaultLogger = NewLogger(ReportCaller())
|
||||
|
||||
l.Logf(logger.InfoLevel, "testing: %s", "WithReportCaller")
|
||||
logger.Logf(logger.InfoLevel, "testing: %s", "WithReportCaller")
|
||||
}
|
||||
|
||||
func TestWithOut(t *testing.T) {
|
||||
l := NewLogger(WithOut(os.Stdout))
|
||||
logger.DefaultLogger = NewLogger(logger.WithOutput(os.Stdout))
|
||||
|
||||
l.Logf(logger.InfoLevel, "testing: %s", "WithOut")
|
||||
logger.Logf(logger.InfoLevel, "testing: %s", "WithOut")
|
||||
}
|
||||
|
||||
func TestWithDevelopmentMode(t *testing.T) {
|
||||
l := NewLogger(WithDevelopmentMode(), WithTimeFormat(time.Kitchen))
|
||||
logger.DefaultLogger = NewLogger(WithDevelopmentMode(), WithTimeFormat(time.Kitchen))
|
||||
|
||||
l.Logf(logger.InfoLevel, "testing: %s", "DevelopmentMode")
|
||||
logger.Logf(logger.InfoLevel, "testing: %s", "DevelopmentMode")
|
||||
}
|
||||
|
||||
func TestWithFields(t *testing.T) {
|
||||
l := NewLogger()
|
||||
logger.DefaultLogger = NewLogger()
|
||||
|
||||
l.Fields(map[string]interface{}{
|
||||
logger.Fields(map[string]interface{}{
|
||||
"sumo": "demo",
|
||||
"human": true,
|
||||
"age": 99,
|
||||
@ -68,9 +65,9 @@ func TestWithFields(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithError(t *testing.T) {
|
||||
l := NewLogger()
|
||||
logger.DefaultLogger = NewLogger()
|
||||
|
||||
l.Error(errors.New("I am Error")).Logf(logger.ErrorLevel, "testing: %s", "WithError")
|
||||
logger.WithError(errors.New("I am Error")).Logf(logger.ErrorLevel, "testing: %s", "WithError")
|
||||
}
|
||||
|
||||
func TestWithHooks(t *testing.T) {
|
||||
@ -79,7 +76,7 @@ func TestWithHooks(t *testing.T) {
|
||||
e.Str("test", "logged")
|
||||
})
|
||||
|
||||
l := NewLogger(WithHooks([]zerolog.Hook{simpleHook}))
|
||||
logger.DefaultLogger = NewLogger(WithHooks([]zerolog.Hook{simpleHook}))
|
||||
|
||||
l.Logf(logger.InfoLevel, "testing: %s", "WithHooks")
|
||||
logger.Logf(logger.InfoLevel, "testing: %s", "WithHooks")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user