2017-02-07 21:33:23 +00:00
|
|
|
package negroni
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"runtime"
|
|
|
|
"runtime/debug"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
|
|
|
|
type Recovery struct {
|
2017-04-11 15:10:46 +00:00
|
|
|
Logger ALogger
|
2017-02-07 21:33:23 +00:00
|
|
|
PrintStack bool
|
|
|
|
ErrorHandlerFunc func(interface{})
|
|
|
|
StackAll bool
|
|
|
|
StackSize int
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewRecovery returns a new instance of Recovery
|
|
|
|
func NewRecovery() *Recovery {
|
|
|
|
return &Recovery{
|
|
|
|
Logger: log.New(os.Stdout, "[negroni] ", 0),
|
|
|
|
PrintStack: true,
|
|
|
|
StackAll: false,
|
|
|
|
StackSize: 1024 * 8,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
|
|
defer func() {
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
if rw.Header().Get("Content-Type") == "" {
|
|
|
|
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
|
|
}
|
|
|
|
|
|
|
|
rw.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
|
|
|
stack := make([]byte, rec.StackSize)
|
|
|
|
stack = stack[:runtime.Stack(stack, rec.StackAll)]
|
|
|
|
|
|
|
|
f := "PANIC: %s\n%s"
|
|
|
|
rec.Logger.Printf(f, err, stack)
|
|
|
|
|
|
|
|
if rec.PrintStack {
|
|
|
|
fmt.Fprintf(rw, f, err, stack)
|
|
|
|
}
|
|
|
|
|
|
|
|
if rec.ErrorHandlerFunc != nil {
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
rec.Logger.Printf("provided ErrorHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack())
|
|
|
|
rec.Logger.Printf("%s\n", debug.Stack())
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
rec.ErrorHandlerFunc(err)
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
next(rw, r)
|
|
|
|
}
|