Adds error formatting

This commit is contained in:
2015-08-12 19:23:53 +02:00
parent e71418fa92
commit 9a123c9281
3 changed files with 59 additions and 19 deletions

42
error_formatter.go Normal file
View File

@@ -0,0 +1,42 @@
package narco
import (
"fmt"
"net/http"
"golang.org/x/net/context"
)
type narcoKey int
const errorFormatterKey narcoKey = 1
type ErrorFomatter func(ctx context.Context, rw http.ResponseWriter, message interface{}, status int)
func Error(ctx context.Context, rw http.ResponseWriter, message interface{}, status int) {
fmter, ok := ctx.Value(errorFormatterKey).(ErrorFomatter)
if ok == false {
//default to http formatter
http.Error(rw, fmt.Sprintf("%s", message), status)
return
}
fmter(ctx, rw, message, status)
}
var narcoDefaultFormatter ErrorFomatter
func TextErrorFormatter(ctx context.Context, rw http.ResponseWriter, message interface{}, status int) {
rw.Header()["Content-Type"] = []string{"text/plain; charset=utf-8"}
rw.WriteHeader(status)
fmt.Fprintf(rw, "%s", message)
}
func BasicHTMLErrorFormatter(ctx context.Context, rw http.ResponseWriter, message interface{}, status int) {
rw.Header()["Content-Type"] = []string{"text/html; charset=utf-8"}
rw.WriteHeader(status)
fmt.Fprintf(rw, `<!doctype html><html><body><h1>Error %d</h1>%s</body></html>`, status, message)
}
func WithErrorFormatter(ctx context.Context, fmter ErrorFomatter) context.Context {
return context.WithValue(ctx, errorFormatterKey, fmter)
}

View File

@@ -2,7 +2,6 @@ package narco
import (
"fmt"
"io"
"log"
"net/http"
"os"
@@ -12,19 +11,14 @@ import (
"golang.org/x/net/context"
)
type StackResponseFormatter func(w io.Writer, err interface{}, stack []byte)
type StackResponseFormatter func(err interface{}, stack []byte) string
func GoFormatStack(w io.Writer, err interface{}, stack []byte) {
fmt.Fprintf(w, "Server internal error: %s\n%s", err, stack)
func GoFormatStack(err interface{}, stack []byte) string {
return fmt.Sprintf("Server internal error: %s\n%s", err, stack)
}
func HtmlFormatStack(w io.Writer, err interface{}, stack []byte) {
fmt.Fprintf(w, `<html>
<body>
<h1>Server internal error: %s</h1>
<pre>%s</pre>
</body>
</html>`, err, stack)
func HtmlFormatStack(err interface{}, stack []byte) string {
return fmt.Sprintf(`<h2>Server internal error: %s</h2><pre>%s</pre>`, err, stack)
}
type Recoverer struct {
@@ -43,27 +37,26 @@ func NewRecoverer() *Recoverer {
func (rec *Recoverer) Wrap() func(chain.Handler) chain.Handler {
return func(other chain.Handler) chain.Handler {
return chain.HandlerFunc(func(ctx context.Context, h http.ResponseWriter, req *http.Request) {
return chain.HandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) {
defer func() {
err := recover()
if err == nil {
return
}
// h.Header()["Content-Type"] = []string{"text/html; charset=utf-8"}
h.WriteHeader(http.StatusInternalServerError)
stack := make([]byte, 8*1024)
stack = stack[:runtime.Stack(stack, rec.StackOtherGoroutine)]
rec.Logger.Printf("PANIC: %s\n%s", err, stack)
var message string
if rec.ShowStackInResponse != nil {
rec.ShowStackInResponse(h, err, stack)
message = rec.ShowStackInResponse(err, stack)
} else {
fmt.Fprintf(h, "%s\n", http.StatusText(http.StatusInternalServerError))
message = http.StatusText(http.StatusInternalServerError)
}
Error(ctx, rw, message, http.StatusInternalServerError)
}()
other.ServeHTTPContext(ctx, h, req)
other.ServeHTTPContext(ctx, rw, req)
})
}
}

View File

@@ -88,7 +88,12 @@ func (fs *StaticFileServer) ServeHTTP(rw http.ResponseWriter, req *http.Request)
//chain handler interface
func (fs *StaticFileServer) ServeHTTPContext(ctx context.Context, rw http.ResponseWriter, req *http.Request) {
fs.ServeHTTP(rw, req)
err := fs.ServeHTTPError(rw, req)
if err != nil {
fsErr := err.(StaticFileServerError)
//use our own context aware error handler
Error(ctx, rw, err.Error(), fsErr.status)
}
}
// chain wrapper. we just ignore the error, and send the request to