Adds error formatting
This commit is contained in:
42
error_formatter.go
Normal file
42
error_formatter.go
Normal 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)
|
||||
}
|
||||
29
recovery.go
29
recovery.go
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user