| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- package recovery
- import (
- "context"
- "encoding/json"
- "runtime"
- "time"
- "github.com/go-kratos/kratos/v2/errors"
- "github.com/go-kratos/kratos/v2/log"
- "github.com/go-kratos/kratos/v2/middleware"
- )
- // Latency is recovery latency context key
- type Latency struct{}
- // ErrUnknownRequest is unknown request error.
- var ErrUnknownRequest = errors.InternalServer("UNKNOWN", "unknown request error")
- // HandlerFunc is recovery handler func.
- type HandlerFunc func(ctx context.Context, req, err any) error
- // Option is recovery option.
- type Option func(*options)
- type options struct {
- handler HandlerFunc
- }
- // WithHandler with recovery handler.
- func WithHandler(h HandlerFunc) Option {
- return func(o *options) {
- o.handler = h
- }
- }
- // Recovery is a server middleware that recovers from any panics.
- func Recovery(opts ...Option) middleware.Middleware {
- op := options{
- handler: func(context.Context, any, any) error {
- return ErrUnknownRequest
- },
- }
- for _, o := range opts {
- o(&op)
- }
- return func(handler middleware.Handler) middleware.Handler {
- return func(ctx context.Context, req any) (reply any, err error) {
- startTime := time.Now()
- defer func() {
- if rerr := recover(); rerr != nil {
- buf := make([]byte, 64<<10) //nolint:mnd
- n := runtime.Stack(buf, false)
- buf = buf[:n]
- reqJson, _ := json.Marshal(req)
- log.Context(ctx).Errorf("%v: %+v\n%s\n", rerr, string(reqJson), buf)
- ctx = context.WithValue(ctx, Latency{}, time.Since(startTime).Seconds())
- err = op.handler(ctx, req, rerr)
- }
- }()
- return handler(ctx, req)
- }
- }
- }
|