47 lines
1.2 KiB
Go
47 lines
1.2 KiB
Go
package util
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"runtime"
|
|
|
|
"github.com/iand/logfmtr"
|
|
)
|
|
|
|
var (
|
|
reallyCrash = true
|
|
log = logfmtr.New()
|
|
panicErr = errors.New("observed a panic")
|
|
)
|
|
|
|
func HandleCrash() {
|
|
if r := recover(); r != nil {
|
|
logPanic(r)
|
|
if reallyCrash {
|
|
panic(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
|
|
const size = 64 << 10
|
|
stacktrace := make([]byte, size)
|
|
stacktrace = stacktrace[:runtime.Stack(stacktrace, false)]
|
|
if _, ok := r.(string); ok {
|
|
log.Error(panicErr, fmt.Sprintf("%s\n%s", r, stacktrace))
|
|
} else {
|
|
log.Error(panicErr, fmt.Sprintf("%#v (%v)\n%s", r, r, stacktrace))
|
|
}
|
|
}
|