blob: a58d717765cea05e20e3d31c84ad6e03f751c2d7 [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001package 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 the call to writer's Write method is not thread safe.
30// Note that os.File Write operation is using write() syscall which is supposed
31// to be thread-safe on POSIX systems. So there is no need to use this with
32// os.File on such systems as zerolog guaranties to issue a single Write call
33// per log event.
34func SyncWriter(w io.Writer) io.Writer {
35 if lw, ok := w.(LevelWriter); ok {
36 return &syncWriter{lw: lw}
37 }
38 return &syncWriter{lw: levelWriterAdapter{w}}
39}
40
41// Write implements the io.Writer interface.
42func (s *syncWriter) Write(p []byte) (n int, err error) {
43 s.mu.Lock()
44 defer s.mu.Unlock()
45 return s.lw.Write(p)
46}
47
48// WriteLevel implements the LevelWriter interface.
49func (s *syncWriter) WriteLevel(l Level, p []byte) (n int, err error) {
50 s.mu.Lock()
51 defer s.mu.Unlock()
52 return s.lw.WriteLevel(l, p)
53}
54
55type multiLevelWriter struct {
56 writers []LevelWriter
57}
58
59func (t multiLevelWriter) Write(p []byte) (n int, err error) {
60 for _, w := range t.writers {
61 n, err = w.Write(p)
62 if err != nil {
63 return
64 }
65 if n != len(p) {
66 err = io.ErrShortWrite
67 return
68 }
69 }
70 return len(p), nil
71}
72
73func (t multiLevelWriter) WriteLevel(l Level, p []byte) (n int, err error) {
74 for _, w := range t.writers {
75 n, err = w.WriteLevel(l, p)
76 if err != nil {
77 return
78 }
79 if n != len(p) {
80 err = io.ErrShortWrite
81 return
82 }
83 }
84 return len(p), nil
85}
86
87// MultiLevelWriter creates a writer that duplicates its writes to all the
88// provided writers, similar to the Unix tee(1) command. If some writers
89// implement LevelWriter, their WriteLevel method will be used instead of Write.
90func MultiLevelWriter(writers ...io.Writer) LevelWriter {
91 lwriters := make([]LevelWriter, 0, len(writers))
92 for _, w := range writers {
93 if lw, ok := w.(LevelWriter); ok {
94 lwriters = append(lwriters, lw)
95 } else {
96 lwriters = append(lwriters, levelWriterAdapter{w})
97 }
98 }
99 return multiLevelWriter{lwriters}
100}