Skip to content

Commit

Permalink
Add option to override sink and encoder (uber-go#1438)
Browse files Browse the repository at this point in the history
Makes it possible to override/wrap encoder/sink
  • Loading branch information
Dmitry Kropachev authored and dkropachev committed May 26, 2024
1 parent 4425037 commit 9591248
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 7 deletions.
33 changes: 26 additions & 7 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,12 @@ func NewDevelopmentConfig() Config {

// Build constructs a logger from the Config and Options.
func (cfg Config) Build(opts ...Option) (*Logger, error) {
enc, err := cfg.buildEncoder()
enc, err := cfg.buildEncoder(filterOptions[wrapEncoderOption](opts...)...)
if err != nil {
return nil, err
}

sink, errSink, err := cfg.openSinks()
sink, errSink, err := cfg.openSinks(filterOptions[wrapSinkerOption](opts...)...)
if err != nil {
return nil, err
}
Expand All @@ -256,7 +256,7 @@ func (cfg Config) Build(opts ...Option) (*Logger, error) {
cfg.buildOptions(errSink)...,
)
if len(opts) > 0 {
log = log.WithOptions(opts...)
log = log.WithOptions(filterOptions[Option](opts...)...)
}
return log, nil
}
Expand Down Expand Up @@ -312,19 +312,38 @@ func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
return opts
}

func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
func (cfg Config) openSinks(opts ...wrapSinkerOption) (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
sink, closeOut, err := Open(cfg.OutputPaths...)
if err != nil {
return nil, nil, err
}
errSink, _, err := Open(cfg.ErrorOutputPaths...)
errSink, errCloseOut, err := Open(cfg.ErrorOutputPaths...)
if err != nil {
closeOut()
return nil, nil, err
}

for _, opt := range opts {
sink, errSink, err = opt.wrapSink(cfg.OutputPaths, sink, cfg.ErrorOutputPaths, errSink)
if err != nil {
closeOut()
errCloseOut()
return nil, nil, err
}
}
return sink, errSink, nil
}

func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
return newEncoder(cfg.Encoding, cfg.EncoderConfig)
func (cfg Config) buildEncoder(opts ...wrapEncoderOption) (zapcore.Encoder, error) {
enc, err := newEncoder(cfg.Encoding, cfg.EncoderConfig)
if err != nil {
return nil, err
}
for _, opt := range opts {
enc, err = opt.wrapEncoder(cfg.Encoding, cfg.EncoderConfig, enc)
if err != nil {
return nil, err
}
}
return enc, nil
}
38 changes: 38 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,49 @@ import (
"go.uber.org/zap/zapcore"
)

func filterOptions[T Option](in ...Option) []T {
var opts []T
for _, opt := range in {
if o, ok := opt.(T); ok {
opts = append(opts, o)
}
}
return opts
}

// An Option configures a Logger.
type Option interface {
apply(*Logger)
}

// wrapEncoderOption wraps a func to make it satisfy the WrapEncoderOption interface.
type wrapEncoderOption func(encoding string, cfg zapcore.EncoderConfig, encoder zapcore.Encoder) (zapcore.Encoder, error)

func (f wrapEncoderOption) wrapEncoder(encoding string, cfg zapcore.EncoderConfig, encoder zapcore.Encoder) (zapcore.Encoder, error) {
return f(encoding, cfg, encoder)
}

func (f wrapEncoderOption) apply(_ *Logger) {}

// WrapEncoder wraps or replaces the Logger's underlying zapcore.Encoder.
func WrapEncoder(fn func(encoding string, cfg zapcore.EncoderConfig, encoder zapcore.Encoder) (zapcore.Encoder, error)) Option {
return wrapEncoderOption(fn)
}

// wrapEncoderOption wraps a func to make it satisfy the WrapSinkersOption interface.
type wrapSinkerOption func(paths []string, sink zapcore.WriteSyncer, errPath []string, errSink zapcore.WriteSyncer) (zapcore.WriteSyncer, zapcore.WriteSyncer, error)

func (f wrapSinkerOption) wrapSink(paths []string, sink zapcore.WriteSyncer, errPath []string, errSink zapcore.WriteSyncer) (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
return f(paths, sink, errPath, errSink)
}

func (f wrapSinkerOption) apply(_ *Logger) {}

// WrapSinker wraps or replaces the Logger's underlying zapcore.Encoder.
func WrapSinker(fn func(paths []string, sink zapcore.WriteSyncer, errPath []string, errSink zapcore.WriteSyncer) (zapcore.WriteSyncer, zapcore.WriteSyncer, error)) Option {
return wrapSinkerOption(fn)
}

// optionFunc wraps a func so it satisfies the Option interface.
type optionFunc func(*Logger)

Expand Down

0 comments on commit 9591248

Please sign in to comment.