Add a method Exit on Logger that calls `os.Exit` or alternate exit function.

This keeps backward compatibility for static declaration of logger
that does not specify `ExitFunc` field.
This commit is contained in:
Albert Salim 2018-10-10 21:54:15 +08:00
parent 2be620216a
commit 99bc300c8d
5 changed files with 26 additions and 25 deletions

View File

@ -45,11 +45,15 @@ func runHandlers() {
} }
} }
type exitFunc func(int)
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) // Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
func Exit(code int) { func Exit(code int) {
runHandlers() runHandlers()
osExit(code)
}
type exitFunc func(int)
func osExit(code int) {
os.Exit(code) os.Exit(code)
} }

View File

@ -39,24 +39,12 @@ func NewLocal(logger *logrus.Logger) *Hook {
} }
type TestOption func(logger *logrus.Logger)
func FatalPanics(logger *logrus.Logger) {
logger.Exit = func(code int) {
panic(code)
}
}
// NewNullLogger creates a discarding logger and installs the test hook. // NewNullLogger creates a discarding logger and installs the test hook.
func NewNullLogger(options ...TestOption) (*logrus.Logger, *Hook) { func NewNullLogger() (*logrus.Logger, *Hook) {
logger := logrus.New() logger := logrus.New()
logger.Out = ioutil.Discard logger.Out = ioutil.Discard
for _, option := range options {
option(logger)
}
return logger, NewLocal(logger) return logger, NewLocal(logger)
} }

View File

@ -72,13 +72,14 @@ func TestLoggingWithHooksRace(t *testing.T) {
assert.Equal(100, len(entries)) assert.Equal(100, len(entries))
} }
func TestFatalWithPanic(t *testing.T) { func TestFatalWithAlternateExit(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
logger, hook := NewNullLogger(FatalPanics) logger, hook := NewNullLogger()
logger.ExitFunc = func(code int) {}
assert.Nil(hook.LastEntry()) logger.Fatal("something went very wrong")
assert.Equal(0, len(hook.Entries)) assert.Equal(logrus.FatalLevel, hook.LastEntry().Level)
assert.Equal("something went very wrong", hook.LastEntry().Message)
assert.Panics(func() { logger.Fatal("something went wrong") }) assert.Equal(1, len(hook.Entries))
} }

View File

@ -32,8 +32,8 @@ type Logger struct {
mu MutexWrap mu MutexWrap
// Reusable empty entry // Reusable empty entry
entryPool sync.Pool entryPool sync.Pool
// Function to exit the application, defaults to `Exit()` // Function to exit the application, defaults to `osExit()`
Exit exitFunc ExitFunc exitFunc
} }
type MutexWrap struct { type MutexWrap struct {
@ -75,7 +75,7 @@ func New() *Logger {
Formatter: new(TextFormatter), Formatter: new(TextFormatter),
Hooks: make(LevelHooks), Hooks: make(LevelHooks),
Level: InfoLevel, Level: InfoLevel,
Exit: Exit, ExitFunc: osExit,
} }
} }
@ -313,6 +313,14 @@ func (logger *Logger) Panicln(args ...interface{}) {
} }
} }
func (logger *Logger) Exit(code int) {
runHandlers()
if logger.ExitFunc == nil {
logger.ExitFunc = osExit
}
logger.ExitFunc(code)
}
//When file is opened with appending mode, it's safe to //When file is opened with appending mode, it's safe to
//write concurrently to a file (within 4k message on Linux). //write concurrently to a file (within 4k message on Linux).
//In these cases user can choose to disable the lock. //In these cases user can choose to disable the lock.

View File

@ -69,7 +69,7 @@ const (
// PanicLevel level, highest level of severity. Logs and then calls panic with the // PanicLevel level, highest level of severity. Logs and then calls panic with the
// message passed to Debug, Info, ... // message passed to Debug, Info, ...
PanicLevel Level = iota PanicLevel Level = iota
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
// logging level is set to Panic. // logging level is set to Panic.
FatalLevel FatalLevel
// ErrorLevel level. Logs. Used for errors that should definitely be noted. // ErrorLevel level. Logs. Used for errors that should definitely be noted.