Skip to content

Commit

Permalink
✨ Allow fine-grained configuration of log/zap
Browse files Browse the repository at this point in the history
  • Loading branch information
alvaroaleman committed Aug 10, 2019
1 parent 9942957 commit f888841
Showing 1 changed file with 77 additions and 17 deletions.
94 changes: 77 additions & 17 deletions pkg/log/zap/zap.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ import (
"go.uber.org/zap/zapcore"
)

// New returns a brand new Logger configured with Opts
func New(opts ...Opts) logr.Logger {
return zapr.NewLogger(NewRaw(opts...))
}

// Logger is a Logger implementation.
// If development is true, a Zap development config will be used
// (stacktraces on warnings, no sampling), otherwise a Zap production
Expand All @@ -47,27 +52,82 @@ func LoggerTo(destWriter io.Writer, development bool) logr.Logger {
// RawLoggerTo returns a new zap.Logger configured with KubeAwareEncoder
// which logs to a given destination
func RawLoggerTo(destWriter io.Writer, development bool, opts ...zap.Option) *zap.Logger {
// this basically mimics New<type>Config, but with a custom sink
sink := zapcore.AddSync(destWriter)

var enc zapcore.Encoder
var lvl zap.AtomicLevel
if development {
encCfg := zap.NewDevelopmentEncoderConfig()
enc = zapcore.NewConsoleEncoder(encCfg)
lvl = zap.NewAtomicLevelAt(zap.DebugLevel)
opts = append(opts, zap.Development(), zap.AddStacktrace(zap.ErrorLevel))
o := func(o *Options) {
o.DestWritter = destWriter
o.Development = development
o.ZapOpts = opts
}
return NewRaw(o)
}

// Opts allows to manipulate Options
type Opts func(*Options)

// Options contains all possible settings
type Options struct {
// If Development is true, a Zap development config will be used
// (stacktraces on warnings, no sampling), otherwise a Zap production
// config will be used (stacktraces on errors, sampling).
Development bool
// The encoder to use, defaults to console when Development is true
// and JSON otherwise
Encoder zapcore.Encoder
// The destination to write to, defaults to os.Stderr
DestWritter io.Writer
// The level to use, defaults to Debug when Development is true and
// Info otherwise
Level *zap.AtomicLevel
// Raw zap.Options to configure on the underlying zap logger
ZapOpts []zap.Option
}

// addDefaults adds defaults to the Options
func (o *Options) addDefaults() {
if o.DestWritter == nil {
o.DestWritter = os.Stderr
}

if o.Development {
if o.Encoder == nil {
encCfg := zap.NewDevelopmentEncoderConfig()
o.Encoder = zapcore.NewConsoleEncoder(encCfg)
}
if o.Level == nil {
lvl := zap.NewAtomicLevelAt(zap.DebugLevel)
o.Level = &lvl
}
o.ZapOpts = append(o.ZapOpts, zap.Development(), zap.AddStacktrace(zap.ErrorLevel))

} else {
encCfg := zap.NewProductionEncoderConfig()
enc = zapcore.NewJSONEncoder(encCfg)
lvl = zap.NewAtomicLevelAt(zap.InfoLevel)
opts = append(opts, zap.AddStacktrace(zap.WarnLevel),
if o.Encoder == nil {
encCfg := zap.NewProductionEncoderConfig()
o.Encoder = zapcore.NewJSONEncoder(encCfg)
}
if o.Level == nil {
lvl := zap.NewAtomicLevelAt(zap.InfoLevel)
o.Level = &lvl
}
o.ZapOpts = append(o.ZapOpts, zap.AddStacktrace(zap.WarnLevel),
zap.WrapCore(func(core zapcore.Core) zapcore.Core {
return zapcore.NewSampler(core, time.Second, 100, 100)
}))
}
opts = append(opts, zap.AddCallerSkip(1), zap.ErrorOutput(sink))
log := zap.New(zapcore.NewCore(&KubeAwareEncoder{Encoder: enc, Verbose: development}, sink, lvl))
log = log.WithOptions(opts...)
}

// NewRaw returns a new zap.Logger configured with the passed Opts
// or their defaults
func NewRaw(opts ...Opts) *zap.Logger {
o := &Options{}
for _, opt := range opts {
opt(o)
}
o.addDefaults()

// this basically mimics New<type>Config, but with a custom sink
sink := zapcore.AddSync(o.DestWritter)

o.ZapOpts = append(o.ZapOpts, zap.AddCallerSkip(1), zap.ErrorOutput(sink))
log := zap.New(zapcore.NewCore(&KubeAwareEncoder{Encoder: o.Encoder, Verbose: o.Development}, sink, *o.Level))
log = log.WithOptions(o.ZapOpts...)
return log
}

0 comments on commit f888841

Please sign in to comment.