diff --git a/backend/couchdb/db.go b/backend/couchdb/db.go index ce77d07fe..e66386c52 100644 --- a/backend/couchdb/db.go +++ b/backend/couchdb/db.go @@ -79,7 +79,6 @@ func Client(cfg *Config) (*kivik.Client, error) { Username: cfg.User, Password: cfg.Password, }, - &transport.TracingRoundTripper{}, transport.NewDumpRoundTripperEnv(), } if !cfg.DisableRequestLogging { diff --git a/http/jsonapi/generator/generate_handler.go b/http/jsonapi/generator/generate_handler.go index 4182fdb07..77c745e40 100644 --- a/http/jsonapi/generator/generate_handler.go +++ b/http/jsonapi/generator/generate_handler.go @@ -595,31 +595,19 @@ func (g *Generator) buildHandler(method string, op *openapi3.Operation, pattern // recover panics g.Defer().Qual(pkgMaintErrors, "HandleRequest").Call(jen.Lit(handler), jen.Id("w"), jen.Id("r")) - g.Add(auth) - // set tracing context - - ctxStmt := jen.Id("r").Dot("Context").Call() - - if auth != nil { - ctxStmt = jen.Id("ctx") - } - g.Line().Comment("Trace the service function handler execution") g.Id("span").Op(":=").Qual(pkgSentry, "StartSpan").Call( - ctxStmt, jen.Lit("http.server"), jen.Qual(pkgSentry, "WithDescription").Call(jen.Lit(handler))) + jen.Id("r").Dot("Context").Call(), jen.Lit("http.server"), jen.Qual(pkgSentry, "WithDescription").Call(jen.Lit(handler))) g.Defer().Id("span").Dot("Finish").Call() g.Line().Empty() - operator := ":=" - - if auth != nil { - operator = "=" - } - - g.Id("ctx").Op(operator).Id("span").Dot("Context").Call() + // set tracing context + g.Id("ctx").Op(":=").Id("span").Dot("Context").Call() g.Id("r").Op("=").Id("r.WithContext").Call(jen.Id("ctx")) + g.Add(auth) + g.Line().Comment("Setup context, response writer and request type") // response writer @@ -830,7 +818,6 @@ func generateAuthorizationForMultipleSecSchemas(op *openapi3.Operation, secSchem caser := cases.Title(language.Und, cases.NoLower) - r.Line().Var().Id("ctx").Id("context.Context") r.Line().Var().Id("ok").Id("bool") for _, val := range orderedSec { name := val[0] diff --git a/http/jsonapi/generator/internal/pay/open-api_test.go b/http/jsonapi/generator/internal/pay/open-api_test.go index 8bf869462..8f0a30bfe 100644 --- a/http/jsonapi/generator/internal/pay/open-api_test.go +++ b/http/jsonapi/generator/internal/pay/open-api_test.go @@ -207,7 +207,13 @@ func CreatePaymentMethodSEPAHandler(service CreatePaymentMethodSEPAHandlerServic return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("CreatePaymentMethodSEPAHandler", w, r) - var ctx context.Context + // Trace the service function handler execution + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("CreatePaymentMethodSEPAHandler")) + defer span.Finish() + + ctx := span.Context() + r = r.WithContext(ctx) + var ok bool if authBackend.CanAuthorizeOAuth2(r) { @@ -232,13 +238,6 @@ func CreatePaymentMethodSEPAHandler(service CreatePaymentMethodSEPAHandlerServic return } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("CreatePaymentMethodSEPAHandler")) - defer span.Finish() - - ctx = span.Context() - r = r.WithContext(ctx) - // Setup context, response writer and request type writer := createPaymentMethodSEPAResponseWriter{ ResponseWriter: metrics.NewMetric("pay", "/beta/payment-methods/sepa-direct-debit", w, r), @@ -284,7 +283,13 @@ func DeletePaymentMethodHandler(service DeletePaymentMethodHandlerService, authB return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("DeletePaymentMethodHandler", w, r) - var ctx context.Context + // Trace the service function handler execution + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("DeletePaymentMethodHandler")) + defer span.Finish() + + ctx := span.Context() + r = r.WithContext(ctx) + var ok bool if authBackend.CanAuthorizeOAuth2(r) { @@ -303,13 +308,6 @@ func DeletePaymentMethodHandler(service DeletePaymentMethodHandlerService, authB return } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("DeletePaymentMethodHandler")) - defer span.Finish() - - ctx = span.Context() - r = r.WithContext(ctx) - // Setup context, response writer and request type writer := deletePaymentMethodResponseWriter{ ResponseWriter: metrics.NewMetric("pay", "/beta/payment-methods/{paymentMethodId}", w, r), diff --git a/http/jsonapi/generator/internal/poi/open-api_test.go b/http/jsonapi/generator/internal/poi/open-api_test.go index 0ee675e0b..4585aad94 100644 --- a/http/jsonapi/generator/internal/poi/open-api_test.go +++ b/http/jsonapi/generator/internal/poi/open-api_test.go @@ -429,18 +429,18 @@ func DeduplicatePoiHandler(service DeduplicatePoiHandlerService, authBackend Aut return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("DeduplicatePoiHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("DeduplicatePoiHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("DeduplicatePoiHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:update") + if !ok { + return + } + // Setup context, response writer and request type writer := deduplicatePoiResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/admin/poi/dedupe", w, r), @@ -486,18 +486,18 @@ func MovePoiAtPositionHandler(service MovePoiAtPositionHandlerService, authBacke return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("MovePoiAtPositionHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("MovePoiAtPositionHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("MovePoiAtPositionHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:update") + if !ok { + return + } + // Setup context, response writer and request type writer := movePoiAtPositionResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/admin/poi/move", w, r), @@ -543,18 +543,18 @@ func GetAppsHandler(service GetAppsHandlerService, authBackend AuthorizationBack return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetAppsHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetAppsHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetAppsHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getAppsResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps", w, r), @@ -620,18 +620,18 @@ func CreateAppHandler(service CreateAppHandlerService, authBackend Authorization return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("CreateAppHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:create") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("CreateAppHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("CreateAppHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:create") + if !ok { + return + } + // Setup context, response writer and request type writer := createAppResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps", w, r), @@ -677,18 +677,18 @@ func CheckForPaceAppHandler(service CheckForPaceAppHandlerService, authBackend A return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("CheckForPaceAppHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("CheckForPaceAppHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("CheckForPaceAppHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") + if !ok { + return + } + // Setup context, response writer and request type writer := checkForPaceAppResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps/query", w, r), @@ -746,18 +746,18 @@ func DeleteAppHandler(service DeleteAppHandlerService, authBackend Authorization return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("DeleteAppHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:delete") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("DeleteAppHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("DeleteAppHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:delete") + if !ok { + return + } + // Setup context, response writer and request type writer := deleteAppResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps/{appID}", w, r), @@ -809,18 +809,18 @@ func GetAppHandler(service GetAppHandlerService, authBackend AuthorizationBacken return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetAppHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetAppHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetAppHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getAppResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps/{appID}", w, r), @@ -872,18 +872,18 @@ func UpdateAppHandler(service UpdateAppHandlerService, authBackend Authorization return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("UpdateAppHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("UpdateAppHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("UpdateAppHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:update") + if !ok { + return + } + // Setup context, response writer and request type writer := updateAppResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps/{appID}", w, r), @@ -938,18 +938,18 @@ func GetAppPOIsRelationshipsHandler(service GetAppPOIsRelationshipsHandlerServic return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetAppPOIsRelationshipsHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetAppPOIsRelationshipsHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetAppPOIsRelationshipsHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getAppPOIsRelationshipsResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps/{appID}/relationships/pois", w, r), @@ -1001,18 +1001,18 @@ func UpdateAppPOIsRelationshipsHandler(service UpdateAppPOIsRelationshipsHandler return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("UpdateAppPOIsRelationshipsHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("UpdateAppPOIsRelationshipsHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("UpdateAppPOIsRelationshipsHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:apps:update") + if !ok { + return + } + // Setup context, response writer and request type writer := updateAppPOIsRelationshipsResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/apps/{appID}/relationships/pois", w, r), @@ -1067,18 +1067,18 @@ func GetDuplicatesKMLHandler(service GetDuplicatesKMLHandlerService, authBackend return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetDuplicatesKMLHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:dumps:duplicatemap") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetDuplicatesKMLHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetDuplicatesKMLHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:dumps:duplicatemap") + if !ok { + return + } + // Setup context, response writer and request type writer := getDuplicatesKMLResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/datadumps/duplicatemap/{countryCode}", w, r), @@ -1130,18 +1130,18 @@ func GetPoisDumpHandler(service GetPoisDumpHandlerService, authBackend Authoriza return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetPoisDumpHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:dumps:pois") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetPoisDumpHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetPoisDumpHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:dumps:pois") + if !ok { + return + } + // Setup context, response writer and request type writer := getPoisDumpResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/datadumps/pois", w, r), @@ -1191,18 +1191,18 @@ func DeleteGasStationReferenceStatusHandler(service DeleteGasStationReferenceSta return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("DeleteGasStationReferenceStatusHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations.references:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("DeleteGasStationReferenceStatusHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("DeleteGasStationReferenceStatusHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations.references:update") + if !ok { + return + } + // Setup context, response writer and request type writer := deleteGasStationReferenceStatusResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/delivery/gas-stations/{gasStationId}/reference-status/{reference}", w, r), @@ -1259,18 +1259,18 @@ func PutGasStationReferenceStatusHandler(service PutGasStationReferenceStatusHan return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("PutGasStationReferenceStatusHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations.references:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("PutGasStationReferenceStatusHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("PutGasStationReferenceStatusHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations.references:update") + if !ok { + return + } + // Setup context, response writer and request type writer := putGasStationReferenceStatusResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/delivery/gas-stations/{gasStationId}/reference-status/{reference}", w, r), @@ -1330,18 +1330,18 @@ func GetEventsHandler(service GetEventsHandlerService, authBackend Authorization return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetEventsHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:events:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetEventsHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetEventsHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:events:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getEventsResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/events", w, r), @@ -1403,18 +1403,18 @@ func GetGasStationsHandler(service GetGasStationsHandlerService, authBackend Aut return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetGasStationsHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetGasStationsHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetGasStationsHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getGasStationsResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/gas-stations", w, r), @@ -1500,18 +1500,18 @@ func GetGasStationHandler(service GetGasStationHandlerService, authBackend Autho return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetGasStationHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetGasStationHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetGasStationHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getGasStationResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/gas-stations/{id}", w, r), @@ -1567,18 +1567,18 @@ func GetPriceHistoryHandler(service GetPriceHistoryHandlerService, authBackend A return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetPriceHistoryHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetPriceHistoryHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetPriceHistoryHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getPriceHistoryResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/gas-stations/{id}/fuel-price-histories/{fuel_type}", w, r), @@ -1647,18 +1647,18 @@ func GetGasStationFuelTypeNameMappingHandler(service GetGasStationFuelTypeNameMa return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetGasStationFuelTypeNameMappingHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetGasStationFuelTypeNameMappingHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetGasStationFuelTypeNameMappingHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getGasStationFuelTypeNameMappingResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/gas-stations/{id}/fueltype", w, r), @@ -1714,18 +1714,18 @@ func GetMetadataFiltersHandler(service GetMetadataFiltersHandlerService, authBac return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetMetadataFiltersHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetMetadataFiltersHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetMetadataFiltersHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:gas-stations:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getMetadataFiltersResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/meta", w, r), @@ -1779,18 +1779,18 @@ func GetPoisHandler(service GetPoisHandlerService, authBackend AuthorizationBack return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetPoisHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetPoisHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetPoisHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getPoisResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/pois", w, r), @@ -1852,18 +1852,18 @@ func GetPoiHandler(service GetPoiHandlerService, authBackend AuthorizationBacken return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetPoiHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetPoiHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetPoiHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getPoiResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/pois/{poiId}", w, r), @@ -1915,18 +1915,18 @@ func ChangePoiHandler(service ChangePoiHandlerService, authBackend Authorization return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("ChangePoiHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("ChangePoiHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("ChangePoiHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:pois:update") + if !ok { + return + } + // Setup context, response writer and request type writer := changePoiResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/pois/{poiId}", w, r), @@ -1981,18 +1981,18 @@ func GetPoliciesHandler(service GetPoliciesHandlerService, authBackend Authoriza return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetPoliciesHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:policies:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetPoliciesHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetPoliciesHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:policies:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getPoliciesResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/policies", w, r), @@ -2058,18 +2058,18 @@ func CreatePolicyHandler(service CreatePolicyHandlerService, authBackend Authori return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("CreatePolicyHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:policies:create") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("CreatePolicyHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("CreatePolicyHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:policies:create") + if !ok { + return + } + // Setup context, response writer and request type writer := createPolicyResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/policies", w, r), @@ -2115,18 +2115,18 @@ func GetPolicyHandler(service GetPolicyHandlerService, authBackend Authorization return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetPolicyHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:policies:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetPolicyHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetPolicyHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:policies:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getPolicyResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/policies/{policyId}", w, r), @@ -2238,18 +2238,18 @@ func GetSourcesHandler(service GetSourcesHandlerService, authBackend Authorizati return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetSourcesHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetSourcesHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetSourcesHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getSourcesResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/sources", w, r), @@ -2311,18 +2311,18 @@ func CreateSourceHandler(service CreateSourceHandlerService, authBackend Authori return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("CreateSourceHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:create") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("CreateSourceHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("CreateSourceHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:create") + if !ok { + return + } + // Setup context, response writer and request type writer := createSourceResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/sources", w, r), @@ -2368,18 +2368,18 @@ func DeleteSourceHandler(service DeleteSourceHandlerService, authBackend Authori return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("DeleteSourceHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:delete") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("DeleteSourceHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("DeleteSourceHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:delete") + if !ok { + return + } + // Setup context, response writer and request type writer := deleteSourceResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/sources/{sourceId}", w, r), @@ -2431,18 +2431,18 @@ func GetSourceHandler(service GetSourceHandlerService, authBackend Authorization return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetSourceHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetSourceHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetSourceHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getSourceResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/sources/{sourceId}", w, r), @@ -2494,18 +2494,18 @@ func UpdateSourceHandler(service UpdateSourceHandlerService, authBackend Authori return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("UpdateSourceHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:update") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("UpdateSourceHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("UpdateSourceHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:sources:update") + if !ok { + return + } + // Setup context, response writer and request type writer := updateSourceResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/sources/{sourceId}", w, r), @@ -2560,18 +2560,18 @@ func GetSubscriptionsHandler(service GetSubscriptionsHandlerService, authBackend return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetSubscriptionsHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:subscriptions:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetSubscriptionsHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetSubscriptionsHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:subscriptions:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getSubscriptionsResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/subscriptions", w, r), @@ -2617,18 +2617,18 @@ func DeleteSubscriptionHandler(service DeleteSubscriptionHandlerService, authBac return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("DeleteSubscriptionHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:subscriptions:delete") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("DeleteSubscriptionHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("DeleteSubscriptionHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:subscriptions:delete") + if !ok { + return + } + // Setup context, response writer and request type writer := deleteSubscriptionResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/subscriptions/{id}", w, r), @@ -2668,18 +2668,18 @@ func StoreSubscriptionHandler(service StoreSubscriptionHandlerService, authBacke return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("StoreSubscriptionHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:subscriptions:create") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("StoreSubscriptionHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("StoreSubscriptionHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:subscriptions:create") + if !ok { + return + } + // Setup context, response writer and request type writer := storeSubscriptionResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/beta/subscriptions/{id}", w, r), @@ -2725,18 +2725,18 @@ func GetTilesHandler(service GetTilesHandlerService, authBackend AuthorizationBa return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetTilesHandler", w, r) - ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:tiles:read") - if !ok { - return - } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetTilesHandler")) + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetTilesHandler")) defer span.Finish() - ctx = span.Context() + ctx := span.Context() r = r.WithContext(ctx) + ctx, ok := authBackend.AuthorizeOAuth2(r, w, "poi:tiles:read") + if !ok { + return + } + // Setup context, response writer and request type writer := getTilesResponseWriter{ ResponseWriter: metrics.NewMetric("poi", "/v1/tiles/query", w, r), diff --git a/http/jsonapi/generator/internal/securitytest/open-api_test.go b/http/jsonapi/generator/internal/securitytest/open-api_test.go index e8157fc08..45a7315a2 100644 --- a/http/jsonapi/generator/internal/securitytest/open-api_test.go +++ b/http/jsonapi/generator/internal/securitytest/open-api_test.go @@ -46,7 +46,13 @@ func GetTestHandler(service GetTestHandlerService, authBackend AuthorizationBack return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer errors.HandleRequest("GetTestHandler", w, r) - var ctx context.Context + // Trace the service function handler execution + span := sentry.StartSpan(r.Context(), "http.server", sentry.WithDescription("GetTestHandler")) + defer span.Finish() + + ctx := span.Context() + r = r.WithContext(ctx) + var ok bool if authBackend.CanAuthorizeOAuth2(r) { @@ -65,13 +71,6 @@ func GetTestHandler(service GetTestHandlerService, authBackend AuthorizationBack return } - // Trace the service function handler execution - span := sentry.StartSpan(ctx, "http.server", sentry.WithDescription("GetTestHandler")) - defer span.Finish() - - ctx = span.Context() - r = r.WithContext(ctx) - // Setup context, response writer and request type writer := getTestResponseWriter{ ResponseWriter: metrics.NewMetric("securitytest", "/beta/test", w, r), diff --git a/http/router.go b/http/router.go index 63fd344b7..2531c5b1f 100755 --- a/http/router.go +++ b/http/router.go @@ -45,14 +45,6 @@ func Router() *mux.Router { // last resort error handler r.Use(errors.Handler()) - // this second handler is needed in order to have access to data managed by the log handler from above - r.Use(tracing.TraceLogHandler( - // no tracing for these prefixes - "/metrics", - "/health", - "/debug", - )) - r.Use(locale.Handler()) // report use of external dependencies diff --git a/http/transport/attempt_round_tripper.go b/http/transport/attempt_round_tripper.go index 1212a8799..77a78cafa 100644 --- a/http/transport/attempt_round_tripper.go +++ b/http/transport/attempt_round_tripper.go @@ -4,8 +4,11 @@ package transport import ( "context" + "fmt" "net/http" "sync/atomic" + + "github.com/getsentry/sentry-go" ) type ctxkey int @@ -29,7 +32,16 @@ func (l *attemptRoundTripper) RoundTrip(req *http.Request) (*http.Response, erro a := atomic.AddInt32(&l.attempt, 1) ctx := context.WithValue(req.Context(), attemptKey, a) - return l.Transport().RoundTrip(req.WithContext(ctx)) + resp, err := l.Transport().RoundTrip(req.WithContext(ctx)) + + if a > 0 { + transaction := sentry.TransactionFromContext(req.Context()) + if transaction != nil { + transaction.SetData("attempt", fmt.Sprintf("%d", a)) + } + } + + return resp, err } func attemptFromCtx(ctx context.Context) int32 { diff --git a/http/transport/default_transport.go b/http/transport/default_transport.go index e2aa57cd6..8a1bd52e2 100644 --- a/http/transport/default_transport.go +++ b/http/transport/default_transport.go @@ -8,7 +8,6 @@ func NewDefaultTransportChain() *RoundTripperChain { return Chain( &ExternalDependencyRoundTripper{}, NewDefaultRetryRoundTripper(), - &TracingRoundTripper{}, &LoggingRoundTripper{}, &LocaleRoundTripper{}, &RequestIDRoundTripper{}, @@ -24,7 +23,6 @@ func NewDefaultTransportChainWithExternalName(name string) *RoundTripperChain { return Chain( &ExternalDependencyRoundTripper{name: name}, NewDefaultRetryRoundTripper(), - &TracingRoundTripper{}, &LoggingRoundTripper{}, &LocaleRoundTripper{}, &RequestIDRoundTripper{}, diff --git a/http/transport/tracing_round_tripper.go b/http/transport/tracing_round_tripper.go deleted file mode 100755 index def73d2f1..000000000 --- a/http/transport/tracing_round_tripper.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright © 2019 by PACE Telematics GmbH. All rights reserved. - -package transport - -import ( - "fmt" - "net/http" - - "github.com/getsentry/sentry-go" -) - -// TracingRoundTripper implements a chainable round tripper for tracing -type TracingRoundTripper struct { - transport http.RoundTripper -} - -// Transport returns the RoundTripper to make HTTP requests -func (l *TracingRoundTripper) Transport() http.RoundTripper { - return l.transport -} - -// SetTransport sets the RoundTripper to make HTTP requests -func (l *TracingRoundTripper) SetTransport(rt http.RoundTripper) { - l.transport = rt -} - -// RoundTrip executes a HTTP request with distributed tracing -func (l *TracingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - ctx := req.Context() - - hub := sentry.GetHubFromContext(ctx) - if hub == nil { - // Check the concurrency guide for more details: https://docs.sentry.io/platforms/go/concurrency/ - hub = sentry.CurrentHub().Clone() - ctx = sentry.SetHubOnContext(ctx, hub) - } - - options := []sentry.SpanOption{ - // Set the OP based on values from https://develop.sentry.dev/sdk/performance/span-operations/ - sentry.WithOpName("http.client"), - sentry.ContinueFromRequest(req), - sentry.WithTransactionSource(sentry.SourceURL), - } - - span := sentry.StartTransaction(ctx, fmt.Sprintf("%s %s", req.Method, req.URL.Path), options...) - defer span.Finish() - - ctx = span.Context() - - resp, err := l.Transport().RoundTrip(req.WithContext(ctx)) - - attempt := attemptFromCtx(ctx) - if attempt > 0 { - span.SetData("attempt", int(attempt)) - } - if err != nil { - span.SetData("error", err) - return nil, err - } - - span.SetData("code", resp.StatusCode) - - return resp, nil -} diff --git a/http/transport/tracing_round_tripper_test.go b/http/transport/tracing_round_tripper_test.go deleted file mode 100644 index a4e99813f..000000000 --- a/http/transport/tracing_round_tripper_test.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright © 2019 by PACE Telematics GmbH. All rights reserved. - -package transport - -import ( - "errors" - "net/http" - "net/http/httptest" - "testing" - - "github.com/getsentry/sentry-go" - _ "github.com/pace/bricks/maintenance/tracing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestTracingRoundTripper(t *testing.T) { - err := sentry.Init(sentry.ClientOptions{ - EnableTracing: true, - TracesSampleRate: 1.0, - }) - require.NoError(t, err) - - t.Run("With successful response", func(t *testing.T) { - l := &TracingRoundTripper{} - tr := &recordingTransportWithResponse{statusCode: 202} - l.SetTransport(tr) - - req := httptest.NewRequest("GET", "/foo", nil) - - _, err := l.RoundTrip(req) - require.NoError(t, err) - - require.NotNil(t, tr.span) - - _, ok := tr.span.Data["attempt"] - assert.False(t, ok) - - code, ok := tr.span.Data["code"] - assert.True(t, ok) - assert.Equal(t, 202, code) - - assert.Equal(t, "GET /foo", tr.span.Name) - }) - - t.Run("With error response", func(t *testing.T) { - l := &TracingRoundTripper{} - e := errors.New("some error") - tr := &recordingTransportWithError{err: e} - l.SetTransport(tr) - - req := httptest.NewRequest("GET", "/bar", nil) - _, err := l.RoundTrip(req) - - assert.Equal(t, err, e) - assert.Equal(t, "GET /bar", tr.span.Name) - - val, ok := tr.span.Data["error"] - assert.True(t, ok) - assert.Equal(t, val, e) - }) - - t.Run("With retries", func(t *testing.T) { - tr := &retriedTransport{statusCodes: []int{502, 503, 200}} - l := Chain(NewDefaultRetryRoundTripper(), &TracingRoundTripper{}) - l.Final(tr) - - req := httptest.NewRequest("GET", "/bar", nil) - - _, err := l.RoundTrip(req) - require.NoError(t, err) - - span := sentry.TransactionFromContext(tr.ctx) - require.NotNil(t, span) - - assert.Equal(t, "GET /bar", span.Name) - - val, ok := span.Data["attempt"] - assert.True(t, ok) - assert.Equal(t, 3, val) - }) -} - -type recordingTransportWithResponse struct { - span *sentry.Span - statusCode int -} - -func (t *recordingTransportWithResponse) RoundTrip(req *http.Request) (*http.Response, error) { - t.span = sentry.TransactionFromContext(req.Context()) - resp := &http.Response{StatusCode: t.statusCode} - - return resp, nil -} - -type recordingTransportWithError struct { - span *sentry.Span - err error -} - -func (t *recordingTransportWithError) RoundTrip(req *http.Request) (*http.Response, error) { - t.span = sentry.TransactionFromContext(req.Context()) - - return nil, t.err -} diff --git a/maintenance/log/handler.go b/maintenance/log/handler.go index 0063dddc7..8d320eb16 100755 --- a/maintenance/log/handler.go +++ b/maintenance/log/handler.go @@ -132,6 +132,11 @@ func RequestIDHandler(fieldKey, headerName string) func(next http.Handler) http. ctx = hlog.WithValue(ctx, id) r = r.WithContext(ctx) + transaction := sentry.TransactionFromContext(ctx) + if transaction != nil { + transaction.SetData("http.request.id", id.String()) + } + // log requests with request id log := zerolog.Ctx(ctx) log.UpdateContext(func(c zerolog.Context) zerolog.Context { diff --git a/maintenance/tracing/tracing.go b/maintenance/tracing/tracing.go index c0c2f6f91..09326711f 100755 --- a/maintenance/tracing/tracing.go +++ b/maintenance/tracing/tracing.go @@ -3,9 +3,9 @@ package tracing import ( - "fmt" "net/http" "os" + "strings" "github.com/getsentry/sentry-go" "github.com/pace/bricks/maintenance/log" @@ -19,6 +19,14 @@ func init() { Environment: os.Getenv("ENVIRONMENT"), EnableTracing: true, TracesSampleRate: 1.0, + BeforeSendTransaction: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event { + // Drop request body. + if event.Request != nil { + event.Request.Data = "" + } + + return event + }, }) if err != nil { log.Fatalf("sentry.Init: %v", err) @@ -32,32 +40,39 @@ type traceHandler struct { // Trace the service function handler execution func (h *traceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - - hub := sentry.GetHubFromContext(ctx) - if hub == nil { - // Check the concurrency guide for more details: https://docs.sentry.io/platforms/go/concurrency/ - hub = sentry.CurrentHub().Clone() - ctx = sentry.SetHubOnContext(ctx, hub) - } + hub := sentry.CurrentHub() options := []sentry.SpanOption{ - // Set the OP based on values from https://develop.sentry.dev/sdk/performance/span-operations/ + sentry.ContinueTrace(hub, r.Header.Get(sentry.SentryTraceHeader), r.Header.Get(sentry.SentryBaggageHeader)), sentry.WithOpName("http.server"), - sentry.ContinueFromRequest(r), sentry.WithTransactionSource(sentry.SourceURL), + sentry.WithSpanOrigin(sentry.SpanOriginStdLib), } - span := sentry.StartTransaction(ctx, - fmt.Sprintf("%s %s", r.Method, r.URL.Path), + transaction := sentry.StartTransaction(ctx, + getHTTPSpanName(r), options..., ) + transaction.SetData("http.request.method", r.Method) - defer span.Finish() - - ctx = span.Context() ww := mutil.WrapWriter(w) - h.next.ServeHTTP(ww, r.WithContext(ctx)) + defer func() { + status := ww.Status() + bytesWritten := ww.BytesWritten() + transaction.Status = sentry.HTTPtoSpanStatus(status) + + transaction.SetData("http.response.status_code", status) + transaction.SetData("http.response.content_length", bytesWritten) + transaction.SetData("http.request.url", r.URL.String()) + + transaction.Finish() + }() + + hub.Scope().SetRequest(r) + r = r.WithContext(transaction.Context()) + + h.next.ServeHTTP(ww, r) } // Handler generates a tracing handler that decodes the current trace from the wire. @@ -70,36 +85,17 @@ func Handler(ignoredPrefixes ...string) func(http.Handler) http.Handler { }, ignoredPrefixes...) } -type traceLogHandler struct { - next http.Handler -} - -// Trace the service function handler execution -func (h *traceLogHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - span := sentry.TransactionFromContext(r.Context()) - - if span != nil { - span.SetData("req_id", log.RequestIDFromContext(r.Context())) - span.SetData("path", r.URL.Path) - span.SetData("method", r.Method) - } - - ww := mutil.WrapWriter(w) - - h.next.ServeHTTP(ww, r) +// getHTTPSpanName grab needed fields from *http.Request to generate a span name for `http.server` span op. +func getHTTPSpanName(r *http.Request) string { + if r.Pattern != "" { + // If value does not start with HTTP methods, add them. + // The method and the path should be separated by a space. + if parts := strings.SplitN(r.Pattern, " ", 2); len(parts) == 1 { + return r.Method + " " + r.Pattern + } - if span != nil { - span.SetData("bytes", ww.BytesWritten()) - span.SetData("status_code", ww.Status()) + return r.Pattern } -} -// TraceLogHandler generates a tracing handler that adds logging data to existing handler. -// The tracing handler will not start traces for the list of ignoredPrefixes. -func TraceLogHandler(ignoredPrefixes ...string) func(http.Handler) http.Handler { - return util.NewIgnorePrefixMiddleware(func(next http.Handler) http.Handler { - return &traceLogHandler{ - next: next, - } - }, ignoredPrefixes...) + return r.Method + " " + r.URL.Path }