1package zerolog 2 3import ( 4 "io" 5 "sync" 6) 7 8// LevelWriter defines as interface a writer may implement in order 9// to receive level information with payload. 10type LevelWriter interface { 11 io.Writer 12 WriteLevel(level Level, p []byte) (n int, err error) 13} 14 15type levelWriterAdapter struct { 16 io.Writer 17} 18 19func (lw levelWriterAdapter) WriteLevel(l Level, p []byte) (n int, err error) { 20 return lw.Write(p) 21} 22 23type syncWriter struct { 24 mu sync.Mutex 25 lw LevelWriter 26} 27 28// SyncWriter wraps w so that each call to Write is synchronized with a mutex. 29// This syncer can be used to wrap the call to writer's Write method if it is 30// not thread safe. Note that you do not need this wrapper for os.File Write 31// operations on POSIX and Windows systems as they are already thread-safe. 32func SyncWriter(w io.Writer) io.Writer { 33 if lw, ok := w.(LevelWriter); ok { 34 return &syncWriter{lw: lw} 35 } 36 return &syncWriter{lw: levelWriterAdapter{w}} 37} 38 39// Write implements the io.Writer interface. 40func (s *syncWriter) Write(p []byte) (n int, err error) { 41 s.mu.Lock() 42 defer s.mu.Unlock() 43 return s.lw.Write(p) 44} 45 46// WriteLevel implements the LevelWriter interface. 47func (s *syncWriter) WriteLevel(l Level, p []byte) (n int, err error) { 48 s.mu.Lock() 49 defer s.mu.Unlock() 50 return s.lw.WriteLevel(l, p) 51} 52 53type multiLevelWriter struct { 54 writers []LevelWriter 55} 56 57func (t multiLevelWriter) Write(p []byte) (n int, err error) { 58 for _, w := range t.writers { 59 n, err = w.Write(p) 60 if err != nil { 61 return 62 } 63 if n != len(p) { 64 err = io.ErrShortWrite 65 return 66 } 67 } 68 return len(p), nil 69} 70 71func (t multiLevelWriter) WriteLevel(l Level, p []byte) (n int, err error) { 72 for _, w := range t.writers { 73 n, err = w.WriteLevel(l, p) 74 if err != nil { 75 return 76 } 77 if n != len(p) { 78 err = io.ErrShortWrite 79 return 80 } 81 } 82 return len(p), nil 83} 84 85// MultiLevelWriter creates a writer that duplicates its writes to all the 86// provided writers, similar to the Unix tee(1) command. If some writers 87// implement LevelWriter, their WriteLevel method will be used instead of Write. 88func MultiLevelWriter(writers ...io.Writer) LevelWriter { 89 lwriters := make([]LevelWriter, 0, len(writers)) 90 for _, w := range writers { 91 if lw, ok := w.(LevelWriter); ok { 92 lwriters = append(lwriters, lw) 93 } else { 94 lwriters = append(lwriters, levelWriterAdapter{w}) 95 } 96 } 97 return multiLevelWriter{lwriters} 98} 99