88 lines
2.1 KiB
Go
88 lines
2.1 KiB
Go
|
package sentryecho
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"github.com/getsentry/sentry-go"
|
||
|
"github.com/labstack/echo/v4"
|
||
|
)
|
||
|
|
||
|
const valuesKey = "sentry"
|
||
|
|
||
|
type handler struct {
|
||
|
repanic bool
|
||
|
waitForDelivery bool
|
||
|
timeout time.Duration
|
||
|
}
|
||
|
|
||
|
type Options struct {
|
||
|
// Repanic configures whether Sentry should repanic after recovery, in most cases it should be set to true,
|
||
|
// as echo includes it's own Recover middleware what handles http responses.
|
||
|
Repanic bool
|
||
|
// WaitForDelivery configures whether you want to block the request before moving forward with the response.
|
||
|
// Because Echo's `Recover` handler doesn't restart the application,
|
||
|
// it's safe to either skip this option or set it to `false`.
|
||
|
WaitForDelivery bool
|
||
|
// Timeout for the event delivery requests.
|
||
|
Timeout time.Duration
|
||
|
}
|
||
|
|
||
|
// New returns a function that satisfies echo.HandlerFunc interface
|
||
|
// It can be used with Use() methods.
|
||
|
func New(options Options) echo.MiddlewareFunc {
|
||
|
handler := handler{
|
||
|
repanic: false,
|
||
|
timeout: time.Second * 2,
|
||
|
waitForDelivery: false,
|
||
|
}
|
||
|
|
||
|
if options.Repanic {
|
||
|
handler.repanic = true
|
||
|
}
|
||
|
|
||
|
if options.Timeout != 0 {
|
||
|
handler.timeout = options.Timeout
|
||
|
}
|
||
|
|
||
|
if options.WaitForDelivery {
|
||
|
handler.waitForDelivery = true
|
||
|
}
|
||
|
|
||
|
return handler.handle
|
||
|
}
|
||
|
|
||
|
func (h *handler) handle(next echo.HandlerFunc) echo.HandlerFunc {
|
||
|
return func(ctx echo.Context) error {
|
||
|
hub := sentry.CurrentHub().Clone()
|
||
|
hub.Scope().SetRequest(ctx.Request())
|
||
|
ctx.Set(valuesKey, hub)
|
||
|
defer h.recoverWithSentry(hub, ctx.Request())
|
||
|
return next(ctx)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (h *handler) recoverWithSentry(hub *sentry.Hub, r *http.Request) {
|
||
|
if err := recover(); err != nil {
|
||
|
eventID := hub.RecoverWithContext(
|
||
|
context.WithValue(r.Context(), sentry.RequestContextKey, r),
|
||
|
err,
|
||
|
)
|
||
|
if eventID != nil && h.waitForDelivery {
|
||
|
hub.Flush(h.timeout)
|
||
|
}
|
||
|
if h.repanic {
|
||
|
panic(err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// GetHubFromContext retrieves attached *sentry.Hub instance from echo.Context.
|
||
|
func GetHubFromContext(ctx echo.Context) *sentry.Hub {
|
||
|
if hub, ok := ctx.Get(valuesKey).(*sentry.Hub); ok {
|
||
|
return hub
|
||
|
}
|
||
|
return nil
|
||
|
}
|