mirror of
https://github.com/rclone/rclone.git
synced 2026-10-05 12:32:29 -04:00
log: fix race when adding a log output while logging
Handle read the list of extra outputs without holding the mutex, so calling AddOutput while logging caused a data race. This reads the extra outputs once under the mutex.
This commit is contained in:
1 parent
10cede9f7f
commit
67ec40a809
2 files changed
+16
-5
No files matched your search
+7
-5
@@ -360,17 +360,19 @@ func (h *OutputHandler) Handle(ctx context.Context, r slog.Record) (err error) {
|
||||
buf *bytes.Buffer
|
||||
)
|
||||
|
||||
// Read the format under the mutex once so it is consistent
|
||||
// throughout this call. The mutex is released before calling
|
||||
// jsonLog/textLog (which may re-acquire it) to avoid deadlock.
|
||||
// Read the format and the extra outputs under the mutex once
|
||||
// so they are consistent throughout this call. The mutex is
|
||||
// released before calling jsonLog/textLog (which may re-acquire
|
||||
// it) to avoid deadlock.
|
||||
h.mu.Lock()
|
||||
format := h.format
|
||||
outputExtra := h.outputExtra
|
||||
h.mu.Unlock()
|
||||
|
||||
// Check whether we need to build Text or JSON logs or both
|
||||
needJSON := format&logFormatJSON != 0
|
||||
needText := !needJSON
|
||||
for _, out := range h.outputExtra {
|
||||
for _, out := range outputExtra {
|
||||
if out.json {
|
||||
needJSON = true
|
||||
} else {
|
||||
@@ -413,7 +415,7 @@ func (h *OutputHandler) Handle(ctx context.Context, r slog.Record) (err error) {
|
||||
}
|
||||
|
||||
// Log to any additional destinations required
|
||||
for _, out := range h.outputExtra {
|
||||
for _, out := range outputExtra {
|
||||
if out.json {
|
||||
out.output(r.Level, bufJSON.String())
|
||||
} else {
|
||||
|
||||
@@ -346,6 +346,15 @@ func TestOutputHandlerConcurrency(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
// Goroutine calling AddOutput alternating JSON and text
|
||||
wg.Go(func() {
|
||||
noop := func(_ slog.Level, _ string) {}
|
||||
for j := range 20 {
|
||||
h.AddOutput(j%2 == 0, noop)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
})
|
||||
|
||||
// Use a channel with a timeout to detect deadlocks
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
|
||||
Reference in new issue
Block a user