gqlgen's DefaultRecover prints the panic and debug.PrintStack() to stderr, so the log collector stores every stack line as a separate, level-less entry. Recover logs the panic as a single ERROR record via slog.Default() with panic, stack and path attributes, records it on the active span with status Error, and returns the generic "internal system error" without leaking the panic text. Install with srv.SetRecoverFunc(otelsetup.Recover). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6eVuR4Yt3m7TbDTDwyZJi
42 lines
1.3 KiB
Go
42 lines
1.3 KiB
Go
package otelsetup
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"runtime/debug"
|
|
|
|
"github.com/99designs/gqlgen/graphql"
|
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
"go.opentelemetry.io/otel/codes"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
// Recover is a gqlgen recover function, installed with srv.SetRecoverFunc(otelsetup.Recover).
|
|
// Unlike graphql.DefaultRecover, which prints the stack to stderr line by line, it logs the
|
|
// panic as a single structured ERROR record (via slog.Default) with the stack as an attribute,
|
|
// records it on the active span and marks the span as failed. The client gets the same generic
|
|
// "internal system error" as with the default, without the panic text.
|
|
func Recover(ctx context.Context, err any) error {
|
|
stack := string(debug.Stack())
|
|
panicErr, ok := err.(error)
|
|
if !ok {
|
|
panicErr = fmt.Errorf("%v", err)
|
|
}
|
|
|
|
attrs := []any{
|
|
slog.String("panic", panicErr.Error()),
|
|
slog.String("stack", stack),
|
|
}
|
|
if fc := graphql.GetFieldContext(ctx); fc != nil {
|
|
attrs = append(attrs, slog.String("path", fc.Path().String()))
|
|
}
|
|
slog.Default().ErrorContext(ctx, "recovered panic in graphql resolver", attrs...)
|
|
|
|
span := trace.SpanFromContext(ctx)
|
|
span.RecordError(panicErr, trace.WithStackTrace(true))
|
|
span.SetStatus(codes.Error, "panic: "+panicErr.Error())
|
|
|
|
return gqlerror.Errorf("internal system error")
|
|
}
|