Add SyncWriter utility type for non-thread-safe writers

This commit is contained in:
Olivier Poitrey 2017-05-19 09:07:33 -07:00
parent 5ebf00efab
commit af9dd4ec23
2 changed files with 46 additions and 3 deletions

8
log.go
View File

@ -139,7 +139,13 @@ type Logger struct {
counter *uint32 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 { func New(w io.Writer) Logger {
if w == nil { if w == nil {
panic("w is nil") panic("w is nil")

View File

@ -1,6 +1,9 @@
package zerolog package zerolog
import "io" import (
"io"
"sync"
)
// LevelWriter defines as interface a writer may implement in order // LevelWriter defines as interface a writer may implement in order
// to receive level information with payload. // to receive level information with payload.
@ -13,10 +16,44 @@ type levelWriterAdapter struct {
io.Writer 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) 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 { type multiLevelWriter struct {
writers []LevelWriter writers []LevelWriter
} }