errors: Log includes file and line number of panics

This commit is contained in:
Matthew Holt 2015-05-05 15:48:10 -06:00
parent 97e702b963
commit 857b4f90d9

View File

@ -7,6 +7,8 @@ import (
"log" "log"
"net/http" "net/http"
"os" "os"
"runtime"
"strings"
"github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware"
) )
@ -20,12 +22,7 @@ type ErrorHandler struct {
} }
func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
defer func() { defer h.recovery(w, r)
if rec := recover(); rec != nil {
h.Log.Printf("[PANIC %s] %v", r.URL.String(), rec)
h.errorPage(w, http.StatusInternalServerError)
}
}()
status, err := h.Next.ServeHTTP(w, r) status, err := h.Next.ServeHTTP(w, r)
@ -78,4 +75,40 @@ func (h ErrorHandler) errorPage(w http.ResponseWriter, code int) {
http.Error(w, defaultBody, code) http.Error(w, defaultBody, code)
} }
func (h ErrorHandler) recovery(w http.ResponseWriter, r *http.Request) {
rec := recover()
if rec == nil {
return
}
// Obtain source of panic
// From: https://gist.github.com/swdunlop/9629168
var name, file string // function name, file name
var line int
var pc [16]uintptr
n := runtime.Callers(3, pc[:])
for _, pc := range pc[:n] {
fn := runtime.FuncForPC(pc)
if fn == nil {
continue
}
file, line = fn.FileLine(pc)
name = fn.Name()
if !strings.HasPrefix(name, "runtime.") {
break
}
}
// Trim file path
delim := "/caddy/"
pkgPathPos := strings.Index(file, delim)
if pkgPathPos > -1 && len(file) > pkgPathPos+len(delim) {
file = file[pkgPathPos+len(delim):]
}
// Currently we don't use the function name, as file:line is more conventional
h.Log.Printf("[PANIC %s] %s:%d - %v", r.URL.String(), file, line, rec)
h.errorPage(w, http.StatusInternalServerError)
}
const DefaultLogFilename = "error.log" const DefaultLogFilename = "error.log"