Repository: uber-go/zap
File: options.go (Go)

Code before:
func AddStacktrace(lvl zapcore.LevelEnabler) Option {
	return optionFunc(func(log *Logger) {
		log.addStack = lvl
	})
}

// IncreaseLevel increase the level of the logger. It has no effect if
// the passed in level tries to decrease the level of the logger.
func IncreaseLevel(lvl zapcore.LevelEnabler) Option {
	return optionFunc(func(log *Logger) {
		core, err := zapcore.NewIncreaseLevelCore(log.core, lvl)
		if err != nil {
			fmt.Fprintf(log.errorOutput, "failed to IncreaseLevel: %v\n", err)
		} else {
			log.core = core
		}
	})
}

// OnFatal sets the action to take on fatal logs.
func OnFatal(action zapcore.CheckWriteAction) Option {
	return optionFunc(func(log *Logger) {
		log.onFatal = action
	})
}

// WithClock specifies the clock used by the logger to determine the current
// time for logged entries. Defaults to the system clock with time.Now.
func WithClock(clock zapcore.Clock) Option {
	return optionFunc(func(log *Logger) {
		log.clock = clock
	})
}


Review comment (refactor):
The documentation should probably call out that users of the logging package expect execution to end at `Fatal`, and so it's recommended that this either:
 * Exits the process
 * OR exits the goroutine (more for testing) where execution of the goroutine stops, but it can be used for testing.

It's pretty common to see code like:
```go
resp, err = [...]
if err != nil {
  logger.Fatal(err)
}

data, err := ioutil.ReadAll(resp.Body)
```

This code would panic, but could be other cases where data ends up getting corrupt etc. It's similar to catching panics, but a little riskier since it doesn't even half execution of the specific goroutine that calls `Fatal`.

Should we make it more difficult to allow execution to continue by disallowing `WriteThenNoop` for this case (user can still specify their own hook).

One other option is to always `runtime.Goexit` at minimum after an `onFatal`, that completely disallows execution to continue for the goroutine calling `Fatal`, but may be too restrictive, it could simplify testing to allow continue execution after capturing that a `Fatal` happened, because the test is confident that there's no other logic that would be inadvertently executed.

Code after:
func AddStacktrace(lvl zapcore.LevelEnabler) Option {
	return optionFunc(func(log *Logger) {
		log.addStack = lvl
	})
}

// IncreaseLevel increase the level of the logger. It has no effect if
// the passed in level tries to decrease the level of the logger.
func IncreaseLevel(lvl zapcore.LevelEnabler) Option {
	return optionFunc(func(log *Logger) {
		core, err := zapcore.NewIncreaseLevelCore(log.core, lvl)
		if err != nil {
			fmt.Fprintf(log.errorOutput, "failed to IncreaseLevel: %v\n", err)
		} else {
			log.core = core
		}
	})
}

// OnFatal sets the action to take on fatal logs.
// Deprecated: Use WithFatalHook instead.
func OnFatal(action zapcore.CheckWriteAction) Option {
	return WithFatalHook(action)
}

// WithFatalHook sets a CheckWriteHook to run on fatal logs.
func WithFatalHook(hook zapcore.CheckWriteHook) Option {
	return optionFunc(func(log *Logger) {
		log.onFatal = hook
	})
}

// WithClock specifies the clock used by the logger to determine the current
// time for logged entries. Defaults to the system clock with time.Now.
func WithClock(clock zapcore.Clock) Option {
	return optionFunc(func(log *Logger) {
		log.clock = clock
	})
}