Improves error management

This commit is contained in:
Manu Mtz-Almeida 2014-07-08 00:16:41 +02:00
parent b5ddd484de
commit 3295c6e9c4
2 changed files with 45 additions and 16 deletions

54
gin.go
View File

@ -24,18 +24,25 @@ const (
MIMEPlain = "text/plain" MIMEPlain = "text/plain"
) )
const (
ErrorTypeInternal = 1 << iota
ErrorTypeExternal = 1 << iota
ErrorTypeAll = 0xffffffff
)
type ( type (
HandlerFunc func(*Context) HandlerFunc func(*Context)
H map[string]interface{} H map[string]interface{}
// Used internally to collect errors that occurred during an http request. // Used internally to collect errors that occurred during an http request.
ErrorMsg struct { errorMsg struct {
Err string `json:"error"` Err string `json:"error"`
Type uint32 `json:"-"`
Meta interface{} `json:"meta"` Meta interface{} `json:"meta"`
} }
ErrorMsgs []ErrorMsg errorMsgs []errorMsg
Config struct { Config struct {
CacheSize int CacheSize int
@ -48,7 +55,7 @@ type (
Req *http.Request Req *http.Request
Writer ResponseWriter Writer ResponseWriter
Keys map[string]interface{} Keys map[string]interface{}
Errors ErrorMsgs Errors errorMsgs
Params httprouter.Params Params httprouter.Params
Engine *Engine Engine *Engine
handlers []HandlerFunc handlers []HandlerFunc
@ -102,13 +109,25 @@ func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return nil return nil
} }
func (a ErrorMsgs) String() string { func (a errorMsgs) ByType(typ uint32) errorMsgs {
if len(a) == 0 {
return a
}
result := make(errorMsgs, 0, len(a))
for _, msg := range a {
if msg.Type&typ > 0 {
result = append(result, msg)
}
}
return result
}
func (a errorMsgs) String() string {
var buffer bytes.Buffer var buffer bytes.Buffer
for i, msg := range a { for i, msg := range a {
text := fmt.Sprintf("Error #%02d: %s \n Meta: %v\n", (i + 1), msg.Err, msg.Meta) text := fmt.Sprintf("Error #%02d: %s \n Meta: %v\n", (i + 1), msg.Err, msg.Meta)
buffer.WriteString(text) buffer.WriteString(text)
} }
buffer.WriteString("\n")
return buffer.String() return buffer.String()
} }
@ -336,14 +355,19 @@ func (c *Context) Fail(code int, err error) {
c.Abort(code) c.Abort(code)
} }
func (c *Context) ErrorTyped(err error, typ uint32, meta interface{}) {
c.Errors = append(c.Errors, errorMsg{
Err: err.Error(),
Type: typ,
Meta: meta,
})
}
// Attaches an error to the current context. The error is pushed to a list of errors. // Attaches an error to the current context. The error is pushed to a list of errors.
// It's a good idea to call Error for each error that occurred during the resolution of a request. // It's a good idea to call Error for each error that occurred during the resolution of a request.
// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response. // A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
func (c *Context) Error(err error, meta interface{}) { func (c *Context) Error(err error, meta interface{}) {
c.Errors = append(c.Errors, ErrorMsg{ c.ErrorTyped(err, ErrorTypeExternal, meta)
Err: err.Error(),
Meta: meta,
})
} }
func (c *Context) LastError() error { func (c *Context) LastError() error {
@ -441,8 +465,8 @@ func (c *Context) JSON(code int, obj interface{}) {
} }
encoder := json.NewEncoder(c.Writer) encoder := json.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil { if err := encoder.Encode(obj); err != nil {
c.Error(err, obj) c.ErrorTyped(err, ErrorTypeInternal, obj)
http.Error(c.Writer, err.Error(), 500) c.Abort(500)
} }
} }
@ -455,8 +479,8 @@ func (c *Context) XML(code int, obj interface{}) {
} }
encoder := xml.NewEncoder(c.Writer) encoder := xml.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil { if err := encoder.Encode(obj); err != nil {
c.Error(err, obj) c.ErrorTyped(err, ErrorTypeInternal, obj)
http.Error(c.Writer, err.Error(), 500) c.Abort(500)
} }
} }
@ -469,11 +493,11 @@ func (c *Context) HTML(code int, name string, data interface{}) {
c.Writer.WriteHeader(code) c.Writer.WriteHeader(code)
} }
if err := c.Engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil { if err := c.Engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil {
c.Error(err, map[string]interface{}{ c.ErrorTyped(err, ErrorTypeInternal, H{
"name": name, "name": name,
"data": data, "data": data,
}) })
http.Error(c.Writer, err.Error(), 500) c.Abort(500)
} }
} }

View File

@ -7,10 +7,15 @@ import (
) )
func ErrorLogger() HandlerFunc { func ErrorLogger() HandlerFunc {
return ErrorLoggerT(ErrorTypeAll)
}
func ErrorLoggerT(typ uint32) HandlerFunc {
return func(c *Context) { return func(c *Context) {
c.Next() c.Next()
if len(c.Errors) > 0 { errs := c.Errors.ByType(typ)
if len(errs) > 0 {
// -1 status code = do not change current one // -1 status code = do not change current one
c.JSON(-1, c.Errors) c.JSON(-1, c.Errors)
} }