99 lines
2.4 KiB
Go
99 lines
2.4 KiB
Go
|
package zerolog
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// LevelWriter defines as interface a writer may implement in order
|
||
|
// to receive level information with payload.
|
||
|
type LevelWriter interface {
|
||
|
io.Writer
|
||
|
WriteLevel(level Level, p []byte) (n int, err error)
|
||
|
}
|
||
|
|
||
|
type levelWriterAdapter struct {
|
||
|
io.Writer
|
||
|
}
|
||
|
|
||
|
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 used to wrap the call to writer's Write method if it is
|
||
|
// not thread safe. Note that you do not need this wrapper for os.File Write
|
||
|
// operations on POSIX and Windows systems as they are already thread-safe.
|
||
|
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()
|
||
|
defer s.mu.Unlock()
|
||
|
return s.lw.Write(p)
|
||
|
}
|
||
|
|
||
|
// WriteLevel implements the LevelWriter interface.
|
||
|
func (s *syncWriter) WriteLevel(l Level, p []byte) (n int, err error) {
|
||
|
s.mu.Lock()
|
||
|
defer s.mu.Unlock()
|
||
|
return s.lw.WriteLevel(l, p)
|
||
|
}
|
||
|
|
||
|
type multiLevelWriter struct {
|
||
|
writers []LevelWriter
|
||
|
}
|
||
|
|
||
|
func (t multiLevelWriter) Write(p []byte) (n int, err error) {
|
||
|
for _, w := range t.writers {
|
||
|
if _n, _err := w.Write(p); err == nil {
|
||
|
n = _n
|
||
|
if _err != nil {
|
||
|
err = _err
|
||
|
} else if _n != len(p) {
|
||
|
err = io.ErrShortWrite
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return n, err
|
||
|
}
|
||
|
|
||
|
func (t multiLevelWriter) WriteLevel(l Level, p []byte) (n int, err error) {
|
||
|
for _, w := range t.writers {
|
||
|
if _n, _err := w.WriteLevel(l, p); err == nil {
|
||
|
n = _n
|
||
|
if _err != nil {
|
||
|
err = _err
|
||
|
} else if _n != len(p) {
|
||
|
err = io.ErrShortWrite
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return n, err
|
||
|
}
|
||
|
|
||
|
// MultiLevelWriter creates a writer that duplicates its writes to all the
|
||
|
// provided writers, similar to the Unix tee(1) command. If some writers
|
||
|
// implement LevelWriter, their WriteLevel method will be used instead of Write.
|
||
|
func MultiLevelWriter(writers ...io.Writer) LevelWriter {
|
||
|
lwriters := make([]LevelWriter, 0, len(writers))
|
||
|
for _, w := range writers {
|
||
|
if lw, ok := w.(LevelWriter); ok {
|
||
|
lwriters = append(lwriters, lw)
|
||
|
} else {
|
||
|
lwriters = append(lwriters, levelWriterAdapter{w})
|
||
|
}
|
||
|
}
|
||
|
return multiLevelWriter{lwriters}
|
||
|
}
|