aboutsummaryrefslogtreecommitdiff
path: root/echo/middleware/recover_middleware.go
diff options
context:
space:
mode:
Diffstat (limited to 'echo/middleware/recover_middleware.go')
-rw-r--r--echo/middleware/recover_middleware.go113
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 @@
1package middleware
2
3import (
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
18type (
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
43var (
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.
56func Recover() echo.MiddlewareFunc {
57 return RecoverWithConfig(DefaultRecoverConfig)
58}
59
60// RecoverWithConfig returns a Recover middleware with config.
61// See: `Recover()`.
62func 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}