Skip to content
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

chore: Print trace ID in panic when available. #16132

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions pkg/util/server/recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import (
"github.com/grafana/dskit/httpgrpc"
"github.com/grafana/dskit/middleware"
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
"github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/uber/jaeger-client-go"

"github.com/grafana/loki/v3/pkg/querier/queryrange/queryrangebase"
"github.com/grafana/loki/v3/pkg/util/constants"
Expand All @@ -30,20 +32,20 @@ var (
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
defer func() {
if p := recover(); p != nil {
WriteError(onPanic(p), w)
WriteError(onPanic(req.Context(), p), w)
}
}()
next.ServeHTTP(w, req)
})
})
RecoveryGRPCStreamInterceptor = grpc_recovery.StreamServerInterceptor(grpc_recovery.WithRecoveryHandler(onPanic))
RecoveryGRPCUnaryInterceptor = grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandler(onPanic))
RecoveryGRPCStreamInterceptor = grpc_recovery.StreamServerInterceptor(grpc_recovery.WithRecoveryHandlerContext(onPanic))
RecoveryGRPCUnaryInterceptor = grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandlerContext(onPanic))

RecoveryMiddleware queryrangebase.Middleware = queryrangebase.MiddlewareFunc(func(next queryrangebase.Handler) queryrangebase.Handler {
return queryrangebase.HandlerFunc(func(ctx context.Context, req queryrangebase.Request) (res queryrangebase.Response, err error) {
defer func() {
if p := recover(); p != nil {
err = onPanic(p)
err = onPanic(ctx, p)
}
}()
res, err = next.Do(ctx, req)
Expand All @@ -52,11 +54,27 @@ var (
})
)

func onPanic(p interface{}) error {
func onPanic(ctx context.Context, p interface{}) error {
stack := make([]byte, maxStacksize)
stack = stack[:runtime.Stack(stack, true)]
traceID := jaegerTraceID(ctx)

// keep a multiline stack
fmt.Fprintf(os.Stderr, "panic: %v\n%s", p, stack)
fmt.Fprintf(os.Stderr, "panic: %v %s\n%s", p, traceID, stack)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change it to

Suggested change
fmt.Fprintf(os.Stderr, "panic: %v %s\n%s", p, traceID, stack)
fmt.Fprintf(os.Stderr, "panic=%v %s\n%s", p, traceID, stack)

but am afraid that this would break some alerts.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You good do also:

fmt.Fprintf(os.Stderr, `panic:"Look into panic=" panic=%v %s\n%s`, p, traceID, stack)

panicTotal.Inc()
return httpgrpc.Errorf(http.StatusInternalServerError, "error while processing request: %v", p)
}

func jaegerTraceID(ctx context.Context) string {
span := opentracing.SpanFromContext(ctx)
if span == nil {
return ""
}

spanContext, ok := span.Context().(jaeger.SpanContext)
if !ok {
return ""
}

return "traceID=" + spanContext.TraceID().String()
}