-
Notifications
You must be signed in to change notification settings - Fork 33
/
panic.go
57 lines (50 loc) · 1.72 KB
/
panic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package runtime
import (
"fmt"
"net/http"
"github.com/sirupsen/logrus"
)
// PanicHandlers is a list of functions which will be invoked when a panic happens.
var PanicHandlers = []func(interface{}){logPanic}
//must use defer Recover()
//not effective for calling defer func() {Recover()}()
func Recover() {
if r := recover(); r != nil {
for _, fn := range PanicHandlers {
fn(r)
}
}
}
// logPanic logs the caller tree when a panic occurs (except in the special case of http.ErrAbortHandler).
func logPanic(r interface{}) {
if r == http.ErrAbortHandler {
// honor the http.ErrAbortHandler sentinel panic value:
// ErrAbortHandler is a sentinel panic value to abort a handler.
// While any panic from ServeHTTP aborts the response to the client,
// panicking with ErrAbortHandler also suppresses logging of a stack trace to the server's error log.
return
}
// Same as stdlib http server code. Manually allocate stack trace buffer size
// to prevent excessively large logs
stacktrace := GetCallStackTrace()
if _, ok := r.(string); ok {
logrus.Errorf("Observed a panic: %s\n%s", r, stacktrace)
} else {
logrus.Errorf("Observed a panic: %#v (%v)\n%s", r, r, stacktrace)
}
}
// RecoverFromPanic replaces the specified error with an error containing the
// original error, and the call tree when a panic occurs. This enables error
// handlers to handle errors and panics the same way.
func RecoverFromPanic(err *error) {
if r := recover(); r != nil {
// Same as stdlib http server code. Manually allocate stack trace buffer size
// to prevent excessively large logs
stacktrace := GetCallStackTrace()
*err = fmt.Errorf(
"recovered from panic %q. (err=%v) Call stack:\n%s",
r,
*err,
stacktrace)
}
}