100 lines
1.9 KiB
Go
100 lines
1.9 KiB
Go
|
package app
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"net/http"
|
||
|
|
||
|
"github.com/getsentry/raven-go"
|
||
|
"github.com/gin-gonic/gin"
|
||
|
)
|
||
|
|
||
|
// Recovery is a better sentry logger.
|
||
|
func Recovery(client *raven.Client, onlyCrashes bool) gin.HandlerFunc {
|
||
|
return func(c *gin.Context) {
|
||
|
var requestBody []byte
|
||
|
|
||
|
defer func() {
|
||
|
tokenRaw, ex := c.Get("token")
|
||
|
var token string
|
||
|
if ex {
|
||
|
token = tokenRaw.(string)
|
||
|
}
|
||
|
|
||
|
ravenHTTP := raven.NewHttp(c.Request)
|
||
|
if len(requestBody) != 0 {
|
||
|
ravenHTTP.Data = string(requestBody)
|
||
|
}
|
||
|
|
||
|
stackTrace := raven.NewStacktrace(0, 3, []string{"git.zxq.co/ripple"})
|
||
|
|
||
|
ravenUser := &raven.User{
|
||
|
Username: "token " + token,
|
||
|
IP: c.Request.RemoteAddr,
|
||
|
}
|
||
|
|
||
|
flags := map[string]string{
|
||
|
"endpoint": c.Request.RequestURI,
|
||
|
"token": token,
|
||
|
}
|
||
|
|
||
|
if rval := recover(); rval != nil {
|
||
|
var err error
|
||
|
switch rval := rval.(type) {
|
||
|
case string:
|
||
|
err = errors.New(rval)
|
||
|
case error:
|
||
|
err = rval
|
||
|
default:
|
||
|
err = fmt.Errorf("%v - %#v", rval, rval)
|
||
|
}
|
||
|
client.CaptureError(
|
||
|
err,
|
||
|
flags,
|
||
|
stackTrace,
|
||
|
ravenHTTP,
|
||
|
ravenUser,
|
||
|
)
|
||
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||
|
}
|
||
|
if !onlyCrashes {
|
||
|
for _, item := range c.Errors {
|
||
|
client.CaptureError(
|
||
|
item,
|
||
|
flags,
|
||
|
stackTrace,
|
||
|
ravenHTTP,
|
||
|
ravenUser,
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
if c.Request.Method == "POST" && c.Request.URL.Path != "/tokens" &&
|
||
|
c.Request.URL.Path != "/tokens/new" {
|
||
|
var err error
|
||
|
requestBody, err = ioutil.ReadAll(c.Request.Body)
|
||
|
if err != nil {
|
||
|
c.Error(err)
|
||
|
}
|
||
|
c.Request.Body = fakeBody{
|
||
|
r: bytes.NewReader(requestBody),
|
||
|
orig: c.Request.Body,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
c.Next()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type fakeBody struct {
|
||
|
r io.Reader
|
||
|
orig io.ReadCloser
|
||
|
}
|
||
|
|
||
|
func (f fakeBody) Read(p []byte) (int, error) { return f.r.Read(p) }
|
||
|
func (f fakeBody) Close() error { return f.orig.Close() }
|