Skip to content

Commit 4730deb

Browse files
committed
Change LogLevelSetter to LogErrorFunc
LogErrorFunc provides more general interface to handle errors in the recover middleware.
1 parent d4ad69d commit 4730deb

File tree

2 files changed

+55
-30
lines changed

2 files changed

+55
-30
lines changed

middleware/recover.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
)
1010

1111
type (
12-
// LogLevelSetter defines a function to get log level for the recovered value.
13-
LogLevelSetter func(value interface{}) log.Lvl
12+
// LogErrorFunc defines a function for custom logging in the middleware.
13+
LogErrorFunc func(c echo.Context, err error, stack []byte) error
1414

1515
// RecoverConfig defines the config for Recover middleware.
1616
RecoverConfig struct {
@@ -34,9 +34,9 @@ type (
3434
// Optional. Default value 0 (Print).
3535
LogLevel log.Lvl
3636

37-
// LogLevelSetter defines a function to get log level for the recovered value.
38-
// LogLevelSetter has higher priority than LogLevel when it's set.
39-
LogLevelSetter LogLevelSetter
37+
// LogErrorFunc defines a function for custom logging in the middleware.
38+
// If it's set you don't need to provide LogLevel for config.
39+
LogErrorFunc LogErrorFunc
4040
}
4141
)
4242

@@ -48,7 +48,7 @@ var (
4848
DisableStackAll: false,
4949
DisablePrintStack: false,
5050
LogLevel: 0,
51-
LogLevelSetter: nil,
51+
LogErrorFunc: nil,
5252
}
5353
)
5454

@@ -81,15 +81,20 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
8181
if !ok {
8282
err = fmt.Errorf("%v", r)
8383
}
84-
logLevel := config.LogLevel
85-
if config.LogLevelSetter != nil {
86-
logLevel = config.LogLevelSetter(r)
87-
}
88-
stack := make([]byte, config.StackSize)
89-
length := runtime.Stack(stack, !config.DisableStackAll)
84+
var stack []byte
85+
var length int
86+
9087
if !config.DisablePrintStack {
88+
stack = make([]byte, config.StackSize)
89+
length = runtime.Stack(stack, !config.DisableStackAll)
90+
stack = stack[:length]
91+
}
92+
93+
if config.LogErrorFunc != nil {
94+
err = config.LogErrorFunc(c, err, stack)
95+
} else if !config.DisablePrintStack {
9196
msg := fmt.Sprintf("[PANIC RECOVER] %v %s\n", err, stack[:length])
92-
switch logLevel {
97+
switch config.LogLevel {
9398
case log.DEBUG:
9499
c.Logger().Debug(msg)
95100
case log.INFO:

middleware/recover_test.go

+37-17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package middleware
22

33
import (
44
"bytes"
5+
"errors"
56
"fmt"
67
"net/http"
78
"net/http/httptest"
@@ -82,7 +83,7 @@ func TestRecoverWithConfig_LogLevel(t *testing.T) {
8283
}
8384
}
8485

85-
func TestRecoverWithConfig_LogLevelSetter(t *testing.T) {
86+
func TestRecoverWithConfig_LogErrorFunc(t *testing.T) {
8687
e := echo.New()
8788
e.Logger.SetLevel(log.DEBUG)
8889

@@ -93,24 +94,43 @@ func TestRecoverWithConfig_LogLevelSetter(t *testing.T) {
9394
rec := httptest.NewRecorder()
9495
c := e.NewContext(req, rec)
9596

97+
testError := errors.New("test")
9698
config := DefaultRecoverConfig
97-
config.LogLevelSetter = func(value interface{}) log.Lvl {
98-
if s, ok := value.(string); ok {
99-
if s == "test" {
100-
return log.DEBUG
101-
}
99+
config.LogErrorFunc = func(c echo.Context, err error, stack []byte) error {
100+
msg := fmt.Sprintf("[PANIC RECOVER] %v %s\n", err, stack)
101+
if errors.Is(err, testError) {
102+
c.Logger().Debug(msg)
103+
} else {
104+
c.Logger().Error(msg)
102105
}
103-
return log.ERROR
106+
return err
104107
}
105-
h := RecoverWithConfig(config)(echo.HandlerFunc(func(c echo.Context) error {
106-
panic("test")
107-
}))
108-
109-
h(c)
110-
111-
assert.Equal(t, http.StatusInternalServerError, rec.Code)
112108

113-
output := buf.String()
114-
assert.Contains(t, output, "PANIC RECOVER")
115-
assert.Contains(t, output, `"level":"DEBUG"`)
109+
t.Run("first branch case for LogErrorFunc", func(t *testing.T) {
110+
buf.Reset()
111+
h := RecoverWithConfig(config)(echo.HandlerFunc(func(c echo.Context) error {
112+
panic(testError)
113+
}))
114+
115+
h(c)
116+
assert.Equal(t, http.StatusInternalServerError, rec.Code)
117+
118+
output := buf.String()
119+
assert.Contains(t, output, "PANIC RECOVER")
120+
assert.Contains(t, output, `"level":"DEBUG"`)
121+
})
122+
123+
t.Run("else branch case for LogErrorFunc", func(t *testing.T) {
124+
buf.Reset()
125+
h := RecoverWithConfig(config)(echo.HandlerFunc(func(c echo.Context) error {
126+
panic("other")
127+
}))
128+
129+
h(c)
130+
assert.Equal(t, http.StatusInternalServerError, rec.Code)
131+
132+
output := buf.String()
133+
assert.Contains(t, output, "PANIC RECOVER")
134+
assert.Contains(t, output, `"level":"ERROR"`)
135+
})
116136
}

0 commit comments

Comments
 (0)