options.go raw

   1  // Copyright (c) 2016 Uber Technologies, Inc.
   2  //
   3  // Permission is hereby granted, free of charge, to any person obtaining a copy
   4  // of this software and associated documentation files (the "Software"), to deal
   5  // in the Software without restriction, including without limitation the rights
   6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   7  // copies of the Software, and to permit persons to whom the Software is
   8  // furnished to do so, subject to the following conditions:
   9  //
  10  // The above copyright notice and this permission notice shall be included in
  11  // all copies or substantial portions of the Software.
  12  //
  13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19  // THE SOFTWARE.
  20  
  21  package zap
  22  
  23  import (
  24  	"fmt"
  25  
  26  	"go.uber.org/zap/zapcore"
  27  )
  28  
  29  // An Option configures a Logger.
  30  type Option interface {
  31  	apply(*Logger)
  32  }
  33  
  34  // optionFunc wraps a func so it satisfies the Option interface.
  35  type optionFunc func(*Logger)
  36  
  37  func (f optionFunc) apply(log *Logger) {
  38  	f(log)
  39  }
  40  
  41  // WrapCore wraps or replaces the Logger's underlying zapcore.Core.
  42  func WrapCore(f func(zapcore.Core) zapcore.Core) Option {
  43  	return optionFunc(func(log *Logger) {
  44  		log.core = f(log.core)
  45  	})
  46  }
  47  
  48  // Hooks registers functions which will be called each time the Logger writes
  49  // out an Entry. Repeated use of Hooks is additive.
  50  //
  51  // Hooks are useful for simple side effects, like capturing metrics for the
  52  // number of emitted logs. More complex side effects, including anything that
  53  // requires access to the Entry's structured fields, should be implemented as
  54  // a zapcore.Core instead. See zapcore.RegisterHooks for details.
  55  func Hooks(hooks ...func(zapcore.Entry) error) Option {
  56  	return optionFunc(func(log *Logger) {
  57  		log.core = zapcore.RegisterHooks(log.core, hooks...)
  58  	})
  59  }
  60  
  61  // Fields adds fields to the Logger.
  62  func Fields(fs ...Field) Option {
  63  	return optionFunc(func(log *Logger) {
  64  		log.core = log.core.With(fs)
  65  	})
  66  }
  67  
  68  // ErrorOutput sets the destination for errors generated by the Logger. Note
  69  // that this option only affects internal errors; for sample code that sends
  70  // error-level logs to a different location from info- and debug-level logs,
  71  // see the package-level AdvancedConfiguration example.
  72  //
  73  // The supplied WriteSyncer must be safe for concurrent use. The Open and
  74  // zapcore.Lock functions are the simplest ways to protect files with a mutex.
  75  func ErrorOutput(w zapcore.WriteSyncer) Option {
  76  	return optionFunc(func(log *Logger) {
  77  		log.errorOutput = w
  78  	})
  79  }
  80  
  81  // Development puts the logger in development mode, which makes DPanic-level
  82  // logs panic instead of simply logging an error.
  83  func Development() Option {
  84  	return optionFunc(func(log *Logger) {
  85  		log.development = true
  86  	})
  87  }
  88  
  89  // AddCaller configures the Logger to annotate each message with the filename,
  90  // line number, and function name of zap's caller. See also WithCaller.
  91  func AddCaller() Option {
  92  	return WithCaller(true)
  93  }
  94  
  95  // WithCaller configures the Logger to annotate each message with the filename,
  96  // line number, and function name of zap's caller, or not, depending on the
  97  // value of enabled. This is a generalized form of AddCaller.
  98  func WithCaller(enabled bool) Option {
  99  	return optionFunc(func(log *Logger) {
 100  		log.addCaller = enabled
 101  	})
 102  }
 103  
 104  // AddCallerSkip increases the number of callers skipped by caller annotation
 105  // (as enabled by the AddCaller option). When building wrappers around the
 106  // Logger and SugaredLogger, supplying this Option prevents zap from always
 107  // reporting the wrapper code as the caller.
 108  func AddCallerSkip(skip int) Option {
 109  	return optionFunc(func(log *Logger) {
 110  		log.callerSkip += skip
 111  	})
 112  }
 113  
 114  // AddStacktrace configures the Logger to record a stack trace for all messages at
 115  // or above a given level.
 116  func AddStacktrace(lvl zapcore.LevelEnabler) Option {
 117  	return optionFunc(func(log *Logger) {
 118  		log.addStack = lvl
 119  	})
 120  }
 121  
 122  // IncreaseLevel increase the level of the logger. It has no effect if
 123  // the passed in level tries to decrease the level of the logger.
 124  func IncreaseLevel(lvl zapcore.LevelEnabler) Option {
 125  	return optionFunc(func(log *Logger) {
 126  		core, err := zapcore.NewIncreaseLevelCore(log.core, lvl)
 127  		if err != nil {
 128  			fmt.Fprintf(log.errorOutput, "failed to IncreaseLevel: %v\n", err)
 129  		} else {
 130  			log.core = core
 131  		}
 132  	})
 133  }
 134  
 135  // WithPanicHook sets a CheckWriteHook to run on Panic/DPanic logs.
 136  // Zap will call this hook after writing a log statement with a Panic/DPanic level.
 137  //
 138  // For example, the following builds a logger that will exit the current
 139  // goroutine after writing a Panic/DPanic log message, but it will not start a panic.
 140  //
 141  //	zap.New(core, zap.WithPanicHook(zapcore.WriteThenGoexit))
 142  //
 143  // This is useful for testing Panic/DPanic log output.
 144  func WithPanicHook(hook zapcore.CheckWriteHook) Option {
 145  	return optionFunc(func(log *Logger) {
 146  		log.onPanic = hook
 147  	})
 148  }
 149  
 150  // OnFatal sets the action to take on fatal logs.
 151  //
 152  // Deprecated: Use [WithFatalHook] instead.
 153  func OnFatal(action zapcore.CheckWriteAction) Option {
 154  	return WithFatalHook(action)
 155  }
 156  
 157  // WithFatalHook sets a CheckWriteHook to run on fatal logs.
 158  // Zap will call this hook after writing a log statement with a Fatal level.
 159  //
 160  // For example, the following builds a logger that will exit the current
 161  // goroutine after writing a fatal log message, but it will not exit the
 162  // program.
 163  //
 164  //	zap.New(core, zap.WithFatalHook(zapcore.WriteThenGoexit))
 165  //
 166  // It is important that the provided CheckWriteHook stops the control flow at
 167  // the current statement to meet expectations of callers of the logger.
 168  // We recommend calling os.Exit or runtime.Goexit inside custom hooks at
 169  // minimum.
 170  func WithFatalHook(hook zapcore.CheckWriteHook) Option {
 171  	return optionFunc(func(log *Logger) {
 172  		log.onFatal = hook
 173  	})
 174  }
 175  
 176  // WithClock specifies the clock used by the logger to determine the current
 177  // time for logged entries. Defaults to the system clock with time.Now.
 178  func WithClock(clock zapcore.Clock) Option {
 179  	return optionFunc(func(log *Logger) {
 180  		log.clock = clock
 181  	})
 182  }
 183