diff --git a/debug.go b/debug.go index b52356a4..47238928 100644 --- a/debug.go +++ b/debug.go @@ -15,7 +15,7 @@ func IsDebugging() bool { return ginMode == debugCode } -func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) { +func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { if IsDebugging() { nuHandlers := len(handlers) handlerName := nameOfFunction(handlers[nuHandlers-1]) @@ -28,3 +28,13 @@ func debugPrint(format string, values ...interface{}) { debugLogger.Printf(format, values...) } } + +func debugPrintWARNING() { + debugPrint("[WARNING] Running in DEBUG mode! Disable it before going production\n") +} + +func debugPrintError(err error) { + if err != nil { + debugPrint("[ERROR] %v\n", err) + } +} diff --git a/debug_test.go b/debug_test.go index e9605687..4e45f56a 100644 --- a/debug_test.go +++ b/debug_test.go @@ -5,11 +5,17 @@ package gin import ( + "bytes" + "errors" + "io" + "log" "testing" "github.com/stretchr/testify/assert" ) +var cachedDebugLogger *log.Logger = nil + // TODO // func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) { // func debugPrint(format string, values ...interface{}) { @@ -22,3 +28,52 @@ func TestIsDebugging(t *testing.T) { SetMode(TestMode) assert.False(t, IsDebugging()) } + +func TestDebugPrint(t *testing.T) { + var w bytes.Buffer + setup(&w) + defer teardown() + + SetMode(ReleaseMode) + debugPrint("DEBUG this!") + SetMode(TestMode) + debugPrint("DEBUG this!") + assert.Empty(t, w.String()) + + SetMode(DebugMode) + debugPrint("these are %d %s\n", 2, "error messages") + assert.Equal(t, w.String(), "[GIN-debug] these are 2 error messages\n") +} + +func TestDebugPrintError(t *testing.T) { + var w bytes.Buffer + setup(&w) + defer teardown() + + SetMode(DebugMode) + debugPrintError(nil) + assert.Empty(t, w.String()) + + debugPrintError(errors.New("this is an error")) + assert.Equal(t, w.String(), "[GIN-debug] [ERROR] this is an error\n") +} + +func setup(w io.Writer) { + SetMode(DebugMode) + if cachedDebugLogger == nil { + cachedDebugLogger = debugLogger + debugLogger = log.New(w, debugLogger.Prefix(), 0) + } else { + panic("setup failed") + } +} + +func teardown() { + SetMode(TestMode) + if cachedDebugLogger != nil { + debugLogger = cachedDebugLogger + cachedDebugLogger = nil + } else { + panic("teardown failed") + } +} diff --git a/errors.go b/errors.go index 04b6f121..9047f983 100644 --- a/errors.go +++ b/errors.go @@ -10,16 +10,19 @@ import ( ) const ( - ErrorTypeInternal = 1 << iota - ErrorTypeExternal = 1 << iota - ErrorTypeAll = 0xffffffff + ErrorTypePrivate = 1 << iota + ErrorTypePublic = 1 << iota +) + +const ( + ErrorMaskAny = 0xffffffff ) // Used internally to collect errors that occurred during an http request. type errorMsg struct { - Err string `json:"error"` - Type int `json:"-"` - Meta interface{} `json:"meta"` + Error error `json:"error"` + Type int `json:"-"` + Meta interface{} `json:"meta"` } type errorMsgs []errorMsg @@ -37,14 +40,24 @@ func (a errorMsgs) ByType(typ int) errorMsgs { return result } +func (a errorMsgs) Errors() []string { + if len(a) == 0 { + return []string{} + } + errors := make([]string, len(a)) + for i, err := range a { + errors[i] = err.Error.Error() + } + return errors +} + func (a errorMsgs) String() string { if len(a) == 0 { return "" } var buffer bytes.Buffer for i, msg := range a { - text := fmt.Sprintf("Error #%02d: %s\n Meta: %v\n", (i + 1), msg.Err, msg.Meta) - buffer.WriteString(text) + fmt.Fprintf(&buffer, "Error #%02d: %s\n Meta: %v\n", (i + 1), msg.Error, msg.Meta) } return buffer.String() } diff --git a/gin.go b/gin.go index 0cdd10fa..590c7ede 100644 --- a/gin.go +++ b/gin.go @@ -62,6 +62,7 @@ type ( // Returns a new blank Engine instance without any middleware attached. // The most basic configuration func New() *Engine { + debugPrintWARNING() engine := &Engine{ RouterGroup: RouterGroup{ Handlers: nil, @@ -156,16 +157,20 @@ func (engine *Engine) handle(method, path string, handlers HandlersChain) { root.addRoute(path, handlers) } -func (engine *Engine) Run(addr string) error { - debugPrint("[WARNING] Running in DEBUG mode! Disable it before going production") +func (engine *Engine) Run(addr string) (err error) { debugPrint("Listening and serving HTTP on %s\n", addr) - return http.ListenAndServe(addr, engine) + defer debugPrintError(err) + + err = http.ListenAndServe(addr, engine) + return } -func (engine *Engine) RunTLS(addr string, cert string, key string) error { - debugPrint("[WARNING] Running in DEBUG mode! Disable it before going production") +func (engine *Engine) RunTLS(addr string, cert string, key string) (err error) { debugPrint("Listening and serving HTTPS on %s\n", addr) - return http.ListenAndServeTLS(addr, cert, key, engine) + defer debugPrintError(err) + + err = http.ListenAndServe(addr, engine) + return } // ServeHTTP makes the router implement the http.Handler interface. diff --git a/routergroup.go b/routergroup.go index a2316432..7ed7798c 100644 --- a/routergroup.go +++ b/routergroup.go @@ -45,7 +45,7 @@ func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *R func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers HandlersChain) { absolutePath := group.calculateAbsolutePath(relativePath) handlers = group.combineHandlers(handlers) - debugRoute(httpMethod, absolutePath, handlers) + debugPrintRoute(httpMethod, absolutePath, handlers) group.engine.handle(httpMethod, absolutePath, handlers) }