-
Notifications
You must be signed in to change notification settings - Fork 42
Panic interceptor #801
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 interceptor #801
Conversation
WalkthroughAdds unary and stream gRPC panic-recovery interceptors and integrates them into the interceptor chains; panics during request handling are recovered, logged with stack traces, and converted into a standardized gRPC INTERNAL error. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant GRPCServer as gRPC Server
participant InterceptorChain as Interceptor Chain
participant PanicInterceptor as Panic Recovery Interceptor
participant Handler as Request Handler
participant Logger as Logger
Client->>GRPCServer: Send Request
GRPCServer->>InterceptorChain: Invoke Chain (includes PanicInterceptor)
rect rgb(245,250,255)
Note over PanicInterceptor: defer recover() & capture stack
PanicInterceptor->>Handler: Call Handler
end
alt Handler completes normally
Handler-->>PanicInterceptor: Response
PanicInterceptor-->>Client: Response
else Handler panics
Handler->>PanicInterceptor: panic()
PanicInterceptor->>Logger: Log panic + stack trace
Logger-->>PanicInterceptor: Logged
PanicInterceptor-->>Client: Return INTERNAL error (somethingWentWrong)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧬 Code graph analysis (1)internal/interface/grpc/interceptors/panic.go (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/interface/grpc/interceptors/interceptor.go (1)
11-16: Move panic interceptor to the start of the chain for complete protection.The panic interceptor is currently the last (innermost) in the chain, which means it only catches panics from the handler itself. Panics in
errorConverter,unaryMacaroonAuthHandler, orunaryLoggerwill not be caught and will still crash the server.Apply this diff to move the panic interceptor to the outermost position:
func UnaryInterceptor(svc *macaroons.Service) grpc.ServerOption { return grpc.UnaryInterceptor(middleware.ChainUnaryServer( + unaryPanicRecoveryInterceptor(), unaryLogger, unaryMacaroonAuthHandler(svc), errorConverter, - unaryPanicRecoveryInterceptor(), )) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
internal/interface/grpc/interceptors/interceptor.go(2 hunks)internal/interface/grpc/interceptors/panic.go(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/interface/grpc/interceptors/panic.go (1)
pkg/errors/errors.go (1)
INTERNAL_ERROR(208-208)
🔇 Additional comments (4)
internal/interface/grpc/interceptors/panic.go (4)
1-12: LGTM!The package comment clearly describes the purpose, and the imports are appropriate for panic recovery with stack trace logging.
14-14: LGTM!The generic error message appropriately avoids leaking internal details to clients, while the panic value is preserved in metadata for debugging.
33-35: LGTM!The handler invocation and return pattern is correct. The named return parameters ensure the error set in the defer block is properly returned when a panic occurs.
55-57: LGTM!The stream handler invocation follows the correct pattern, with the named return parameter ensuring panic-generated errors are properly returned.
| defer func() { | ||
| if r := recover(); r != nil { | ||
| log.Errorf("panic-recovery middleware recovered from panic: %v", r) | ||
| log.Debugf( | ||
| "panic-recovery middleware recovered from panic: %v", string(debug.Stack()), | ||
| ) | ||
| err = somethingWentWrong.WithMetadata(map[string]any{ | ||
| "error": r, | ||
| }) | ||
| } | ||
| }() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Log stack trace at Error level for production visibility.
The stack trace is currently logged only at Debug level, which may be disabled in production. When investigating production panics, the stack trace is critical for diagnosis.
Apply this diff:
defer func() {
if r := recover(); r != nil {
log.Errorf("panic-recovery middleware recovered from panic: %v", r)
- log.Debugf(
- "panic-recovery middleware recovered from panic: %v", string(debug.Stack()),
- )
+ log.Errorf("Stack trace: %s", string(debug.Stack()))
err = somethingWentWrong.WithMetadata(map[string]any{
"error": r,
})
}
}()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| defer func() { | |
| if r := recover(); r != nil { | |
| log.Errorf("panic-recovery middleware recovered from panic: %v", r) | |
| log.Debugf( | |
| "panic-recovery middleware recovered from panic: %v", string(debug.Stack()), | |
| ) | |
| err = somethingWentWrong.WithMetadata(map[string]any{ | |
| "error": r, | |
| }) | |
| } | |
| }() | |
| defer func() { | |
| if r := recover(); r != nil { | |
| log.Errorf("panic-recovery middleware recovered from panic: %v", r) | |
| log.Errorf("Stack trace: %s", string(debug.Stack())) | |
| err = somethingWentWrong.WithMetadata(map[string]any{ | |
| "error": r, | |
| }) | |
| } | |
| }() |
🤖 Prompt for AI Agents
In internal/interface/grpc/interceptors/panic.go around lines 21-31, the defer
recovery currently logs the panic message at Error level but only logs the stack
trace at Debug level; change it to log the stack trace at Error level so it's
visible in production (keep or optionally also log at Debug), and include the
stack trace in the error metadata as well. Specifically, capture debug.Stack()
into a variable, call log.Errorf with both the panic value and the stack trace,
and add the stack string to the somethingWentWrong.WithMetadata map (e.g.,
"stack": stack) so the error returned contains the stack trace.
Revert the gRPC panic.go interceptor + return an INTERNAL_ERROR in case of recovery.
@altafan please review
Summary by CodeRabbit