New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
panic: runtime error: index out of range [-1] with context logger #443
Comments
I found the issue is not related here to using multiple time the same event but using the same logger across multiple goroutines. |
@afarbos did you find solution? I see some similar panics in logs, but very rare. |
Yes, It started similarly for me, rare and then became a bigger issue. The short story is zerolog is not thread/async-safe. |
It may not be the case with everyone, but I found one conclusive scenario where this will always happen. Zerolog internally uses Now generally while using the Logger, Method chain is suggested that automatically tackles this. However, the Func methods are where there is a possibility of re-use of events. See this block for example. l.Debug().Func(func(e *zerolog.Event) {
e.Int("client-status-code", resp.StatusCode).Msg("Response Status")
headers := zerolog.Dict()
for k, v := range resp.Header {
headers.Strs(k, v)
}
e.Dict("client-headers", headers).Msg("Response Headers")
}) In this case, the Event will be returned to the Pool after the first e.Int...Msg() call. In case multiple goroutines are using Zerolog (sub-loggers or top-level loggers), there is a possibility that it might get the same event and starts using it. Meanwhile the next e.Dict...Msg() call will also try to use the underlying buffer of the same event. This will cause the Data race usually and can cause panics in certain cases. The following test-case when running with package main
import (
"context"
"os"
"sync"
"testing"
"github.com/rs/zerolog"
)
func TestZerologRace(t *testing.T) {
ctx := zerolog.New(os.Stdout).WithContext(context.Background())
var wg sync.WaitGroup
wg.Add(2)
go func(ctx context.Context) {
defer wg.Done()
for i := 0; i < 100000; i++ {
new := zerolog.Ctx(ctx).With().Logger()
new.Info().Func(func(e *zerolog.Event) {
e.Msg("This is it!")
e.Msg("This is it!")
})
}
}(ctx)
go func(ctx context.Context) {
defer wg.Done()
for i := 0; i < 100000; i++ {
new := zerolog.Ctx(ctx).With().Logger()
new.Info().Func(func(e *zerolog.Event) {
e.Msg("This is it!")
e.Msg("This is it!")
})
}
}(ctx)
wg.Wait()
} The solution is simple, you just need to not re-use the events and in the given example, call the Func twice instead. l.Debug().Func(func(e *zerolog.Event) {
e.Int("client-status-code", resp.StatusCode).Msg("Response Status")
})
l.Debug().Func(func(e *zerolog.Event) {
headers := zerolog.Dict()
for k, v := range resp.Header {
headers.Strs(k, v)
}
e.Dict("client-headers", headers).Msg("Response Headers")
}) |
We were seeing a panic, and it's because we're reusing events in zerolog [1]... this stops doing that for that function. [1] rs/zerolog#443 Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
We were seeing a panic, and it's because we're reusing events in zerolog [1]... this stops doing that for that function. [1] rs/zerolog#443 Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
Hello, I encounter a similar issue as #422, #283, #249 and #239.
However, I am always relying on the context logger so I don't see how I would be reusing a similar event or underlying resources expect the logger itself.
Example usage:
I am not sure how this panic is possible today. The buffer seems to always be set looking at the code. I printed the zerolog.Context and it was never empty.
My stacktrace look like:
The text was updated successfully, but these errors were encountered: