diff options
Diffstat (limited to 'echo/middleware/recover_middleware.go')
-rw-r--r-- | echo/middleware/recover_middleware.go | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/echo/middleware/recover_middleware.go b/echo/middleware/recover_middleware.go new file mode 100644 index 0000000..310e146 --- /dev/null +++ b/echo/middleware/recover_middleware.go | |||
@@ -0,0 +1,113 @@ | |||
1 | package middleware | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "net/http" | ||
6 | "runtime" | ||
7 | |||
8 | "github.com/labstack/echo/v4" | ||
9 | "github.com/labstack/echo/v4/middleware" | ||
10 | "github.com/labstack/gommon/log" | ||
11 | ) | ||
12 | |||
13 | // This is mostly copied from the upstream and modified to: | ||
14 | // | ||
15 | // * Report a stack up to 1MB | ||
16 | // * Print the stack trace to the output if in debug | ||
17 | |||
18 | type ( | ||
19 | // RecoverConfig defines the config for Recover middleware. | ||
20 | RecoverConfig struct { | ||
21 | // Skipper defines a function to skip middleware. | ||
22 | Skipper middleware.Skipper | ||
23 | |||
24 | // Size of the stack to be printed. | ||
25 | // Optional. Default value 4KB. | ||
26 | StackSize int `yaml:"stack_size"` | ||
27 | |||
28 | // DisableStackAll disables formatting stack traces of all other goroutines | ||
29 | // into buffer after the trace for the current goroutine. | ||
30 | // Optional. Default value false. | ||
31 | DisableStackAll bool `yaml:"disable_stack_all"` | ||
32 | |||
33 | // DisablePrintStack disables printing stack trace. | ||
34 | // Optional. Default value as false. | ||
35 | DisablePrintStack bool `yaml:"disable_print_stack"` | ||
36 | |||
37 | // LogLevel is log level to printing stack trace. | ||
38 | // Optional. Default value 0 (Print). | ||
39 | LogLevel log.Lvl | ||
40 | } | ||
41 | ) | ||
42 | |||
43 | var ( | ||
44 | // DefaultRecoverConfig is the default Recover middleware config. | ||
45 | DefaultRecoverConfig = RecoverConfig{ | ||
46 | Skipper: middleware.DefaultSkipper, | ||
47 | StackSize: 1024 << 10, // 1 MB | ||
48 | DisableStackAll: false, | ||
49 | DisablePrintStack: false, | ||
50 | LogLevel: 0, | ||
51 | } | ||
52 | ) | ||
53 | |||
54 | // Recover returns a middleware which recovers from panics anywhere in the chain | ||
55 | // and handles the control to the centralized HTTPErrorHandler. | ||
56 | func Recover() echo.MiddlewareFunc { | ||
57 | return RecoverWithConfig(DefaultRecoverConfig) | ||
58 | } | ||
59 | |||
60 | // RecoverWithConfig returns a Recover middleware with config. | ||
61 | // See: `Recover()`. | ||
62 | func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc { | ||
63 | // Defaults | ||
64 | if config.Skipper == nil { | ||
65 | config.Skipper = DefaultRecoverConfig.Skipper | ||
66 | } | ||
67 | if config.StackSize == 0 { | ||
68 | config.StackSize = DefaultRecoverConfig.StackSize | ||
69 | } | ||
70 | |||
71 | return func(next echo.HandlerFunc) echo.HandlerFunc { | ||
72 | return func(c echo.Context) error { | ||
73 | if config.Skipper(c) { | ||
74 | return next(c) | ||
75 | } | ||
76 | |||
77 | defer func() { | ||
78 | if r := recover(); r != nil { | ||
79 | err, ok := r.(error) | ||
80 | if !ok { | ||
81 | err = fmt.Errorf("%v", r) | ||
82 | } | ||
83 | stack := make([]byte, config.StackSize) | ||
84 | length := runtime.Stack(stack, !config.DisableStackAll) | ||
85 | if !config.DisablePrintStack { | ||
86 | msg := fmt.Sprintf("[PANIC RECOVER] %v %s\n", err, stack[:length]) | ||
87 | switch config.LogLevel { | ||
88 | case log.DEBUG: | ||
89 | c.Logger().Debug(msg) | ||
90 | case log.INFO: | ||
91 | c.Logger().Info(msg) | ||
92 | case log.WARN: | ||
93 | c.Logger().Warn(msg) | ||
94 | case log.ERROR: | ||
95 | c.Logger().Error(msg) | ||
96 | case log.OFF: | ||
97 | // None. | ||
98 | default: | ||
99 | c.Logger().Print(msg) | ||
100 | } | ||
101 | } | ||
102 | if c.Echo().Debug { | ||
103 | msg := fmt.Sprintf("%v %s\n", err, stack[:length]) | ||
104 | c.String(http.StatusInternalServerError, msg) | ||
105 | } else { | ||
106 | c.Error(err) | ||
107 | } | ||
108 | } | ||
109 | }() | ||
110 | return next(c) | ||
111 | } | ||
112 | } | ||
113 | } | ||