log: SyncLogger: defer mutex unlocks for panic safety (#974)
Peter Bourgon authored 4 years ago
GitHub committed 4 years ago
64 | 64 |
// progress, the calling goroutine blocks until the syncWriter is available.
|
65 | 65 |
func (w *syncWriter) Write(p []byte) (n int, err error) {
|
66 | 66 |
w.Lock()
|
67 | |
n, err = w.Writer.Write(p)
|
68 | |
w.Unlock()
|
69 | |
return n, err
|
|
67 |
defer w.Unlock()
|
|
68 |
return w.Writer.Write(p)
|
70 | 69 |
}
|
71 | 70 |
|
72 | 71 |
// fdWriter is an io.Writer that also has an Fd method. The most common
|
|
86 | 85 |
// progress, the calling goroutine blocks until the fdSyncWriter is available.
|
87 | 86 |
func (w *fdSyncWriter) Write(p []byte) (n int, err error) {
|
88 | 87 |
w.Lock()
|
89 | |
n, err = w.fdWriter.Write(p)
|
90 | |
w.Unlock()
|
91 | |
return n, err
|
|
88 |
defer w.Unlock()
|
|
89 |
return w.fdWriter.Write(p)
|
92 | 90 |
}
|
93 | 91 |
|
94 | 92 |
// syncLogger provides concurrent safe logging for another Logger.
|
|
109 | 107 |
// progress, the calling goroutine blocks until the syncLogger is available.
|
110 | 108 |
func (l *syncLogger) Log(keyvals ...interface{}) error {
|
111 | 109 |
l.mu.Lock()
|
112 | |
err := l.logger.Log(keyvals...)
|
113 | |
l.mu.Unlock()
|
114 | |
return err
|
|
110 |
defer l.mu.Unlock()
|
|
111 |
return l.logger.Log(keyvals...)
|
115 | 112 |
}
|
80 | 80 |
t.Error("NewSyncWriter does not pass through Fd method")
|
81 | 81 |
}
|
82 | 82 |
}
|
|
83 |
|
|
84 |
func TestSyncLoggerPanic(t *testing.T) {
|
|
85 |
var logger log.Logger
|
|
86 |
logger = log.LoggerFunc(func(...interface{}) error { panic("!") })
|
|
87 |
logger = log.NewSyncLogger(logger)
|
|
88 |
|
|
89 |
f := func() {
|
|
90 |
defer func() {
|
|
91 |
if x := recover(); x != nil {
|
|
92 |
t.Log(x)
|
|
93 |
}
|
|
94 |
}()
|
|
95 |
logger.Log("hello", "world")
|
|
96 |
}
|
|
97 |
|
|
98 |
f()
|
|
99 |
f() // without defer Unlock, this one can deadlock
|
|
100 |
}
|