diff --git a/log.go b/log.go index 88fde42..d19a54a 100644 --- a/log.go +++ b/log.go @@ -139,7 +139,13 @@ type Logger struct { counter *uint32 } -// New creates a root logger with given output writer. +// New creates a root logger with given output writer. If the output writer implements +// the LevelWriter interface, the WriteLevel method will be called instead of the Write +// one. +// +// Each logging operation makes a single call to the Writer's Write method. There is no +// guaranty on access serialization to the Writer. If your Writer is not thread safe, +// you may consider using sync wrapper. func New(w io.Writer) Logger { if w == nil { panic("w is nil") diff --git a/writer.go b/writer.go index 10f133c..75c1b50 100644 --- a/writer.go +++ b/writer.go @@ -1,6 +1,9 @@ package zerolog -import "io" +import ( + "io" + "sync" +) // LevelWriter defines as interface a writer may implement in order // to receive level information with payload. @@ -13,10 +16,44 @@ type levelWriterAdapter struct { io.Writer } -func (lw levelWriterAdapter) WriteLevel(level Level, p []byte) (n int, err error) { +func (lw levelWriterAdapter) WriteLevel(l Level, p []byte) (n int, err error) { return lw.Write(p) } +type syncWriter struct { + mu sync.Mutex + lw LevelWriter +} + +// SyncWriter wraps w so that each call to Write is synchronized with a mutex. +// This syncer can be the call to writer's Write method is not thread safe. +// Note that os.File Write operation is using write() syscall which is supposed +// to be thread-safe on POSIX systems. So there is no need to use this with +// os.File on such systems as zerolog guaranties to issue a single Write call +// per log event. +func SyncWriter(w io.Writer) io.Writer { + if lw, ok := w.(LevelWriter); ok { + return &syncWriter{lw: lw} + } + return &syncWriter{lw: levelWriterAdapter{w}} +} + +// Write implements the io.Writer interface. +func (s *syncWriter) Write(p []byte) (n int, err error) { + s.mu.Lock() + n, err = s.lw.Write(p) + s.mu.Unlock() + return +} + +// WriteLevel implements the LevelWriter interface. +func (s *syncWriter) WriteLevel(l Level, p []byte) (n int, err error) { + s.mu.Lock() + n, err = s.lw.WriteLevel(l, p) + s.mu.Unlock() + return +} + type multiLevelWriter struct { writers []LevelWriter }