diff --git a/logger.go b/logger.go index 9052a8065..f3b64385f 100644 --- a/logger.go +++ b/logger.go @@ -26,8 +26,29 @@ type Logger struct { // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be // logged. `logrus.Debug` is useful in Level Level - // Used to sync writing to the log. - mu sync.Mutex + // Used to sync writing to the log. Locking is enabled by Default + mu MutexWrap +} + +type MutexWrap struct { + lock sync.Mutex + disabled bool +} + +func (mw *MutexWrap) Lock() { + if !mw.disabled { + mw.lock.Lock() + } +} + +func (mw *MutexWrap) Unlock() { + if !mw.disabled { + mw.lock.Unlock() + } +} + +func (mw *MutexWrap) Disable() { + mw.disabled = true } // Creates a new logger. Configuration should be set by changing `Formatter`, @@ -210,3 +231,10 @@ func (logger *Logger) Panicln(args ...interface{}) { NewEntry(logger).Panicln(args...) } } + +//When file is opened with appending mode, it's safe to +//write concurrently to a file (within 4k message on Linux). +//In these cases user can choose to disable the lock. +func (logger *Logger) SetNoLock() { + logger.mu.Disable() +} diff --git a/logger_bench_test.go b/logger_bench_test.go index 28a1a26b4..dd23a3535 100644 --- a/logger_bench_test.go +++ b/logger_bench_test.go @@ -22,6 +22,15 @@ func BenchmarkDummyLogger(b *testing.B) { doLoggerBenchmark(b, nullf, &TextFormatter{DisableColors: true}, smallFields) } +func BenchmarkDummyLoggerNoLock(b *testing.B) { + nullf, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + b.Fatalf("%v", err) + } + defer nullf.Close() + doLoggerBenchmarkNoLock(b, nullf, &TextFormatter{DisableColors: true}, smallFields) +} + func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields Fields) { logger := Logger{ Out: out, @@ -35,3 +44,18 @@ func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields F } }) } + +func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fields Fields) { + logger := Logger{ + Out: out, + Level: InfoLevel, + Formatter: formatter, + } + logger.SetNoLock() + entry := logger.WithFields(fields) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + entry.Info("aaa") + } + }) +}