forked from mirrors/pronouns.cc
feat(backend): also add sentry tracing
This commit is contained in:
parent
b04ed68832
commit
9f266ee1a8
4 changed files with 102 additions and 13 deletions
|
@ -28,7 +28,11 @@ func run(c *cli.Context) error {
|
||||||
if dsn := os.Getenv("SENTRY_DSN"); dsn != "" {
|
if dsn := os.Getenv("SENTRY_DSN"); dsn != "" {
|
||||||
sentry.Init(sentry.ClientOptions{
|
sentry.Init(sentry.ClientOptions{
|
||||||
Dsn: dsn,
|
Dsn: dsn,
|
||||||
|
Debug: true,
|
||||||
Release: server.Tag,
|
Release: server.Tag,
|
||||||
|
EnableTracing: true,
|
||||||
|
TracesSampleRate: 1.0,
|
||||||
|
ProfilesSampleRate: 1.0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
@ -15,16 +14,10 @@ import (
|
||||||
// The inner HandlerFunc additionally returns an error.
|
// The inner HandlerFunc additionally returns an error.
|
||||||
func WrapHandler(hn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc {
|
func WrapHandler(hn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
hub := sentry.CurrentHub().Clone()
|
hub := sentry.GetHubFromContext(r.Context())
|
||||||
|
if hub == nil {
|
||||||
defer func(hub *sentry.Hub, r *http.Request) {
|
hub = sentry.CurrentHub().Clone()
|
||||||
if err := recover(); err != nil {
|
|
||||||
hub.RecoverWithContext(
|
|
||||||
context.WithValue(r.Context(), sentry.RequestContextKey, r),
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}(hub, r)
|
|
||||||
|
|
||||||
err := hn(w, r)
|
err := hn(w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
89
backend/server/sentry.go
Normal file
89
backend/server/sentry.go
Normal file
|
@ -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.Logger)
|
||||||
}
|
}
|
||||||
s.Router.Use(middleware.Recoverer)
|
s.Router.Use(middleware.Recoverer)
|
||||||
|
// add Sentry tracing handler
|
||||||
|
s.Router.Use(s.sentry)
|
||||||
|
|
||||||
// add CORS
|
// add CORS
|
||||||
s.Router.Use(cors.Handler(cors.Options{
|
s.Router.Use(cors.Handler(cors.Options{
|
||||||
AllowedOrigins: []string{"https://*", "http://*"},
|
AllowedOrigins: []string{"https://*", "http://*"},
|
||||||
|
|
Loading…
Reference in a new issue