package orusapi import ( "context" "fmt" "net/http" "runtime/debug" "github.com/getsentry/sentry-go" jsoniter "github.com/json-iterator/go" "github.com/rs/zerolog" ) // CatchPanics catches the panics and log them as errors. func CatchPanics(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { defer func(ctx context.Context) { if r := recover(); r != nil { log := zerolog.Ctx(ctx) exc := zerolog.Dict(). Str("type", fmt.Sprintf("%T", r)) if err, ok := r.(error); ok { exc = exc.AnErr("value", err) } else { exc = exc.Str("value", fmt.Sprintf("%#v", r)) } stack := sentry.NewStacktrace() stack.Frames = stack.Frames[:len(stack.Frames)-1] b, err := jsoniter.Marshal(stack) if err != nil { log.Err(err).Msg("Could not marshal stacktrace, fallback to plain debug.Stack()") b = debug.Stack() exc = exc.Str("plainstack", string(b)) } else { exc = exc.RawJSON("stacktrace", b) } log.Error().Dict("exception", exc).Msg("Caught a panic") rw.WriteHeader(http.StatusInternalServerError) } }(req.Context()) next.ServeHTTP(rw, req) }) }