diff --git a/debug_test.go b/debug_test.go index 05e648f..1e1e522 100644 --- a/debug_test.go +++ b/debug_test.go @@ -18,21 +18,3 @@ func TestIsDebugging(t *testing.T) { SetMode(TestMode) assert.False(t, IsDebugging()) } - -// TODO -// func TestDebugPrint(t *testing.T) { -// buffer := bytes.NewBufferString("") -// debugLogger. -// log.SetOutput(buffer) - -// SetMode(ReleaseMode) -// debugPrint("This is a example") -// assert.Equal(t, buffer.Len(), 0) - -// SetMode(DebugMode) -// debugPrint("This is %s", "a example") -// assert.Equal(t, buffer.String(), "[GIN-debug] This is a example") - -// SetMode(TestMode) -// log.SetOutput(os.Stdout) -// } diff --git a/recovery.go b/recovery.go index 82b76ee..e8b1ba4 100644 --- a/recovery.go +++ b/recovery.go @@ -7,9 +7,9 @@ package gin import ( "bytes" "fmt" + "io" "io/ioutil" "log" - "net/http" "runtime" ) @@ -20,6 +20,31 @@ var ( slash = []byte("/") ) +// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. +// While Gin is in development mode, Recovery will also output the panic as HTML. +func Recovery() HandlerFunc { + return RecoveryWithFile(DefaultWriter) +} + +func RecoveryWithFile(out io.Writer) HandlerFunc { + var logger *log.Logger + if out != nil { + logger = log.New(out, "", log.LstdFlags) + } + return func(c *Context) { + defer func() { + if err := recover(); err != nil { + if logger != nil { + stack := stack(3) + logger.Printf("Gin Panic Recover!! -> %s\n%s\n", err, stack) + } + c.AbortWithStatus(500) + } + }() + c.Next() + } +} + // stack returns a nicely formated stack frame, skipping skip frames func stack(skip int) []byte { buf := new(bytes.Buffer) // the returned data @@ -80,19 +105,3 @@ func function(pc uintptr) []byte { name = bytes.Replace(name, centerDot, dot, -1) return name } - -// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. -// While Gin is in development mode, Recovery will also output the panic as HTML. -func Recovery() HandlerFunc { - return func(c *Context) { - defer func() { - if err := recover(); err != nil { - stack := stack(3) - log.Printf("PANIC: %s\n%s", err, stack) - c.Writer.WriteHeader(http.StatusInternalServerError) - } - }() - - c.Next() - } -} diff --git a/recovery_test.go b/recovery_test.go index 32eb3ee..d471306 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -6,51 +6,37 @@ package gin import ( "bytes" - "log" - "os" "testing" + + "github.com/stretchr/testify/assert" ) // TestPanicInHandler assert that panic has been recovered. func TestPanicInHandler(t *testing.T) { - // SETUP - log.SetOutput(bytes.NewBuffer(nil)) // Disable panic logs for testing - r := New() - r.Use(Recovery()) - r.GET("/recovery", func(_ *Context) { + buffer := new(bytes.Buffer) + router := New() + router.Use(RecoveryWithFile(buffer)) + router.GET("/recovery", func(_ *Context) { panic("Oupps, Houston, we have a problem") }) - // RUN - w := performRequest(r, "GET", "/recovery") - - // restore logging - log.SetOutput(os.Stderr) - - if w.Code != 500 { - t.Errorf("Response code should be Internal Server Error, was: %d", w.Code) - } + w := performRequest(router, "GET", "/recovery") + // TEST + assert.Equal(t, w.Code, 500) + assert.Contains(t, buffer.String(), "Gin Panic Recover!! -> Oupps, Houston, we have a problem") + assert.Contains(t, buffer.String(), "TestPanicInHandler") } // TestPanicWithAbort assert that panic has been recovered even if context.Abort was used. func TestPanicWithAbort(t *testing.T) { - // SETUP - log.SetOutput(bytes.NewBuffer(nil)) - r := New() - r.Use(Recovery()) - r.GET("/recovery", func(c *Context) { + router := New() + router.Use(RecoveryWithFile(nil)) + router.GET("/recovery", func(c *Context) { c.AbortWithStatus(400) panic("Oupps, Houston, we have a problem") }) - // RUN - w := performRequest(r, "GET", "/recovery") - - // restore logging - log.SetOutput(os.Stderr) - + w := performRequest(router, "GET", "/recovery") // TEST - if w.Code != 500 { - t.Errorf("Response code should be Bad request, was: %d", w.Code) - } + assert.Equal(t, w.Code, 500) // NOT SURE }