feat(backend): also add sentry tracing
This commit is contained in:
parent
b04ed68832
commit
9f266ee1a8
|
@ -28,7 +28,11 @@ func run(c *cli.Context) error {
|
|||
if dsn := os.Getenv("SENTRY_DSN"); dsn != "" {
|
||||
sentry.Init(sentry.ClientOptions{
|
||||
Dsn: dsn,
|
||||
Debug: true,
|
||||
Release: server.Tag,
|
||||
EnableTracing: true,
|
||||
TracesSampleRate: 1.0,
|
||||
ProfilesSampleRate: 1.0,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
@ -15,16 +14,10 @@ import (
|
|||
// The inner HandlerFunc additionally returns an error.
|
||||
func WrapHandler(hn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
hub := sentry.CurrentHub().Clone()
|
||||
|
||||
defer func(hub *sentry.Hub, r *http.Request) {
|
||||
if err := recover(); err != nil {
|
||||
hub.RecoverWithContext(
|
||||
context.WithValue(r.Context(), sentry.RequestContextKey, r),
|
||||
err,
|
||||
)
|
||||
hub := sentry.GetHubFromContext(r.Context())
|
||||
if hub == nil {
|
||||
hub = sentry.CurrentHub().Clone()
|
||||
}
|
||||
}(hub, r)
|
||||
|
||||
err := hn(w, r)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
func (s *Server) sentry(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
|
||||
|
||||
ctx := r.Context()
|
||||
hub := sentry.GetHubFromContext(ctx)
|
||||
if hub == nil {
|
||||
hub = sentry.CurrentHub().Clone()
|
||||
ctx = sentry.SetHubOnContext(ctx, hub)
|
||||
}
|
||||
|
||||
options := []sentry.SpanOption{
|
||||
sentry.WithOpName("http.server"),
|
||||
sentry.ContinueFromRequest(r),
|
||||
sentry.WithTransactionSource(sentry.SourceURL),
|
||||
}
|
||||
// We don't mind getting an existing transaction back so we don't need to
|
||||
// check if it is.
|
||||
transaction := sentry.StartTransaction(ctx,
|
||||
fmt.Sprintf("%s %s", r.Method, r.URL.Path),
|
||||
options...,
|
||||
)
|
||||
defer transaction.Finish()
|
||||
r = r.WithContext(transaction.Context())
|
||||
hub.Scope().SetRequest(r)
|
||||
defer recoverWithSentry(hub, r)
|
||||
handler.ServeHTTP(ww, r)
|
||||
|
||||
transaction.Status = httpStatusToSentryStatus(ww.Status())
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
transaction.Name = rctx.RouteMethod + " " + rctx.RoutePattern()
|
||||
})
|
||||
}
|
||||
|
||||
func recoverWithSentry(hub *sentry.Hub, r *http.Request) {
|
||||
if err := recover(); err != nil {
|
||||
hub.RecoverWithContext(
|
||||
context.WithValue(r.Context(), sentry.RequestContextKey, r),
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func httpStatusToSentryStatus(status int) sentry.SpanStatus {
|
||||
// c.f. https://develop.sentry.dev/sdk/event-payloads/span/
|
||||
|
||||
if status >= 200 && status < 400 {
|
||||
return sentry.SpanStatusOK
|
||||
}
|
||||
|
||||
switch status {
|
||||
case 499:
|
||||
return sentry.SpanStatusCanceled
|
||||
case 500:
|
||||
return sentry.SpanStatusInternalError
|
||||
case 400:
|
||||
return sentry.SpanStatusInvalidArgument
|
||||
case 504:
|
||||
return sentry.SpanStatusDeadlineExceeded
|
||||
case 404:
|
||||
return sentry.SpanStatusNotFound
|
||||
case 409:
|
||||
return sentry.SpanStatusAlreadyExists
|
||||
case 403:
|
||||
return sentry.SpanStatusPermissionDenied
|
||||
case 429:
|
||||
return sentry.SpanStatusResourceExhausted
|
||||
case 501:
|
||||
return sentry.SpanStatusUnimplemented
|
||||
case 503:
|
||||
return sentry.SpanStatusUnavailable
|
||||
case 401:
|
||||
return sentry.SpanStatusUnauthenticated
|
||||
default:
|
||||
return sentry.SpanStatusUnknown
|
||||
}
|
||||
}
|
|
@ -50,6 +50,9 @@ func New() (*Server, error) {
|
|||
s.Router.Use(middleware.Logger)
|
||||
}
|
||||
s.Router.Use(middleware.Recoverer)
|
||||
// add Sentry tracing handler
|
||||
s.Router.Use(s.sentry)
|
||||
|
||||
// add CORS
|
||||
s.Router.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: []string{"https://*", "http://*"},
|
||||
|
|
Loading…
Reference in New Issue