From 0d358a4bfae022d15cd12488beb49b2c874c8e0b Mon Sep 17 00:00:00 2001 From: Maximilien Cuony Date: Wed, 18 Mar 2026 16:11:10 +0100 Subject: [PATCH] [monitoring] Add telemetry in router --- cmds/core-service/main.go | 7 +-- .../example/api/common.gen.go | 2 + .../example/api/rid/server.gen.go | 37 +++++++++---- .../example/api/scd/server.gen.go | 53 ++++++++++++------- .../example/run_example.sh | 2 +- interfaces/openapi-to-go-server/generate.py | 10 +++- interfaces/openapi-to-go-server/rendering.py | 13 ++++- .../templates/common.go.template | 2 + .../templates/server.go.template | 14 +++++ pkg/api/auxv1/server.gen.go | 33 +++++++++--- pkg/api/common.gen.go | 2 + pkg/api/ridv1/server.gen.go | 37 +++++++++---- pkg/api/ridv2/server.gen.go | 37 +++++++++---- pkg/api/scdv1/server.gen.go | 53 ++++++++++++------- 14 files changed, 219 insertions(+), 83 deletions(-) diff --git a/cmds/core-service/main.go b/cmds/core-service/main.go index 3d55e4d4c..a3bb768c0 100644 --- a/cmds/core-service/main.go +++ b/cmds/core-service/main.go @@ -317,11 +317,8 @@ func RunHTTPServer(ctx context.Context, ctxCanceler func(), address, locality st handler = authorizer.TokenMiddleware(handler) if *enableOpenTelemetry { - httpSpanName := func(operation string, req *http.Request) string { - return fmt.Sprintf("%s %s", req.Method, req.URL.Path) - } - - handler = otelhttp.NewHandler(handler, "http", otelhttp.WithSpanNameFormatter(httpSpanName)) + // We use the default settings; the APIRouter handler will override the span value accordingly, as it has more information. + handler = otelhttp.NewHandler(handler, "http") } httpServer := &http.Server{ diff --git a/interfaces/openapi-to-go-server/example/api/common.gen.go b/interfaces/openapi-to-go-server/example/api/common.gen.go index 9e0183eda..2512a0dbb 100644 --- a/interfaces/openapi-to-go-server/example/api/common.gen.go +++ b/interfaces/openapi-to-go-server/example/api/common.gen.go @@ -62,6 +62,8 @@ type Route struct { Method string Pattern *regexp.Regexp Handler Handler + Name string + Path string } type PartialRouter interface { diff --git a/interfaces/openapi-to-go-server/example/api/rid/server.gen.go b/interfaces/openapi-to-go-server/example/api/rid/server.gen.go index 78efebe90..4874f61e0 100644 --- a/interfaces/openapi-to-go-server/example/api/rid/server.gen.go +++ b/interfaces/openapi-to-go-server/example/api/rid/server.gen.go @@ -5,6 +5,9 @@ import ( "context" "encoding/json" "example/api" + "fmt" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" "net/http" "regexp" ) @@ -15,10 +18,24 @@ type APIRouter struct { Authorizer api.Authorizer } +var tracer = otel.Tracer("rid.api") + // *rid.APIRouter (type defined above) implements the api.PartialRouter interface func (s *APIRouter) Handle(w http.ResponseWriter, r *http.Request) bool { for _, route := range s.Routes { if route.Method == r.Method && route.Pattern.MatchString(r.URL.Path) { + + span := trace.SpanFromContext(r.Context()) + + if span.IsRecording() { + // Current span is the one from the otelhttp handler + span.SetName(fmt.Sprintf("%s %s", r.Method, route.Path)) + } + + ctx, span := tracer.Start(r.Context(), route.Name) + defer span.End() + r = r.WithContext(ctx) + route.Handler(route.Pattern, w, r) return true } @@ -522,34 +539,34 @@ func MakeAPIRouter(impl Implementation, auth api.Authorizer) APIRouter { router := APIRouter{Implementation: impl, Authorizer: auth, Routes: make([]*api.Route, 10)} pattern := regexp.MustCompile("^/rid/v1/dss/identification_service_areas$") - router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchIdentificationServiceAreas} + router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchIdentificationServiceAreas, Name: "rid.SearchIdentificationServiceAreas", Path: "/rid/v1/dss/identification_service_areas"} pattern = regexp.MustCompile("^/rid/v1/dss/identification_service_areas/(?P[^/]*)$") - router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetIdentificationServiceArea} + router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetIdentificationServiceArea, Name: "rid.GetIdentificationServiceArea", Path: "/rid/v1/dss/identification_service_areas/{id}"} pattern = regexp.MustCompile("^/rid/v1/dss/identification_service_areas/(?P[^/]*)$") - router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateIdentificationServiceArea} + router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateIdentificationServiceArea, Name: "rid.CreateIdentificationServiceArea", Path: "/rid/v1/dss/identification_service_areas/{id}"} pattern = regexp.MustCompile("^/rid/v1/dss/identification_service_areas/(?P[^/]*)/(?P[^/]*)$") - router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateIdentificationServiceArea} + router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateIdentificationServiceArea, Name: "rid.UpdateIdentificationServiceArea", Path: "/rid/v1/dss/identification_service_areas/{id}/{version}"} pattern = regexp.MustCompile("^/rid/v1/dss/identification_service_areas/(?P[^/]*)/(?P[^/]*)$") - router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteIdentificationServiceArea} + router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteIdentificationServiceArea, Name: "rid.DeleteIdentificationServiceArea", Path: "/rid/v1/dss/identification_service_areas/{id}/{version}"} pattern = regexp.MustCompile("^/rid/v1/dss/subscriptions$") - router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchSubscriptions} + router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchSubscriptions, Name: "rid.SearchSubscriptions", Path: "/rid/v1/dss/subscriptions"} pattern = regexp.MustCompile("^/rid/v1/dss/subscriptions/(?P[^/]*)$") - router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription} + router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription, Name: "rid.GetSubscription", Path: "/rid/v1/dss/subscriptions/{id}"} pattern = regexp.MustCompile("^/rid/v1/dss/subscriptions/(?P[^/]*)$") - router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription} + router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription, Name: "rid.CreateSubscription", Path: "/rid/v1/dss/subscriptions/{id}"} pattern = regexp.MustCompile("^/rid/v1/dss/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription} + router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription, Name: "rid.UpdateSubscription", Path: "/rid/v1/dss/subscriptions/{id}/{version}"} pattern = regexp.MustCompile("^/rid/v1/dss/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription} + router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription, Name: "rid.DeleteSubscription", Path: "/rid/v1/dss/subscriptions/{id}/{version}"} return router } diff --git a/interfaces/openapi-to-go-server/example/api/scd/server.gen.go b/interfaces/openapi-to-go-server/example/api/scd/server.gen.go index 07748e116..300abac23 100644 --- a/interfaces/openapi-to-go-server/example/api/scd/server.gen.go +++ b/interfaces/openapi-to-go-server/example/api/scd/server.gen.go @@ -5,6 +5,9 @@ import ( "context" "encoding/json" "example/api" + "fmt" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" "net/http" "regexp" ) @@ -15,10 +18,24 @@ type APIRouter struct { Authorizer api.Authorizer } +var tracer = otel.Tracer("scd.api") + // *scd.APIRouter (type defined above) implements the api.PartialRouter interface func (s *APIRouter) Handle(w http.ResponseWriter, r *http.Request) bool { for _, route := range s.Routes { if route.Method == r.Method && route.Pattern.MatchString(r.URL.Path) { + + span := trace.SpanFromContext(r.Context()) + + if span.IsRecording() { + // Current span is the one from the otelhttp handler + span.SetName(fmt.Sprintf("%s %s", r.Method, route.Path)) + } + + ctx, span := tracer.Start(r.Context(), route.Name) + defer span.End() + r = r.WithContext(ctx) + route.Handler(route.Pattern, w, r) return true } @@ -953,58 +970,58 @@ func MakeAPIRouter(impl Implementation, auth api.Authorizer) APIRouter { router := APIRouter{Implementation: impl, Authorizer: auth, Routes: make([]*api.Route, 18)} pattern := regexp.MustCompile("^/scd/dss/v1/operational_intent_references/query$") - router.Routes[0] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryOperationalIntentReferences} + router.Routes[0] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryOperationalIntentReferences, Name: "scd.QueryOperationalIntentReferences", Path: "/scd/dss/v1/operational_intent_references/query"} pattern = regexp.MustCompile("^/scd/dss/v1/operational_intent_references/(?P[^/]*)$") - router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetOperationalIntentReference} + router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetOperationalIntentReference, Name: "scd.GetOperationalIntentReference", Path: "/scd/dss/v1/operational_intent_references/{entityid}"} pattern = regexp.MustCompile("^/scd/dss/v1/operational_intent_references/(?P[^/]*)$") - router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateOperationalIntentReference} + router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateOperationalIntentReference, Name: "scd.CreateOperationalIntentReference", Path: "/scd/dss/v1/operational_intent_references/{entityid}"} pattern = regexp.MustCompile("^/scd/dss/v1/operational_intent_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateOperationalIntentReference} + router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateOperationalIntentReference, Name: "scd.UpdateOperationalIntentReference", Path: "/scd/dss/v1/operational_intent_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/scd/dss/v1/operational_intent_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteOperationalIntentReference} + router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteOperationalIntentReference, Name: "scd.DeleteOperationalIntentReference", Path: "/scd/dss/v1/operational_intent_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/scd/dss/v1/constraint_references/query$") - router.Routes[5] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryConstraintReferences} + router.Routes[5] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryConstraintReferences, Name: "scd.QueryConstraintReferences", Path: "/scd/dss/v1/constraint_references/query"} pattern = regexp.MustCompile("^/scd/dss/v1/constraint_references/(?P[^/]*)$") - router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetConstraintReference} + router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetConstraintReference, Name: "scd.GetConstraintReference", Path: "/scd/dss/v1/constraint_references/{entityid}"} pattern = regexp.MustCompile("^/scd/dss/v1/constraint_references/(?P[^/]*)$") - router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateConstraintReference} + router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateConstraintReference, Name: "scd.CreateConstraintReference", Path: "/scd/dss/v1/constraint_references/{entityid}"} pattern = regexp.MustCompile("^/scd/dss/v1/constraint_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateConstraintReference} + router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateConstraintReference, Name: "scd.UpdateConstraintReference", Path: "/scd/dss/v1/constraint_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/scd/dss/v1/constraint_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteConstraintReference} + router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteConstraintReference, Name: "scd.DeleteConstraintReference", Path: "/scd/dss/v1/constraint_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/scd/dss/v1/subscriptions/query$") - router.Routes[10] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QuerySubscriptions} + router.Routes[10] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QuerySubscriptions, Name: "scd.QuerySubscriptions", Path: "/scd/dss/v1/subscriptions/query"} pattern = regexp.MustCompile("^/scd/dss/v1/subscriptions/(?P[^/]*)$") - router.Routes[11] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription} + router.Routes[11] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription, Name: "scd.GetSubscription", Path: "/scd/dss/v1/subscriptions/{subscriptionid}"} pattern = regexp.MustCompile("^/scd/dss/v1/subscriptions/(?P[^/]*)$") - router.Routes[12] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription} + router.Routes[12] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription, Name: "scd.CreateSubscription", Path: "/scd/dss/v1/subscriptions/{subscriptionid}"} pattern = regexp.MustCompile("^/scd/dss/v1/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[13] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription} + router.Routes[13] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription, Name: "scd.UpdateSubscription", Path: "/scd/dss/v1/subscriptions/{subscriptionid}/{version}"} pattern = regexp.MustCompile("^/scd/dss/v1/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[14] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription} + router.Routes[14] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription, Name: "scd.DeleteSubscription", Path: "/scd/dss/v1/subscriptions/{subscriptionid}/{version}"} pattern = regexp.MustCompile("^/scd/dss/v1/reports$") - router.Routes[15] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.MakeDssReport} + router.Routes[15] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.MakeDssReport, Name: "scd.MakeDssReport", Path: "/scd/dss/v1/reports"} pattern = regexp.MustCompile("^/scd/dss/v1/uss_availability/(?P[^/]*)$") - router.Routes[16] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetUssAvailability} + router.Routes[16] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetUssAvailability, Name: "scd.GetUssAvailability", Path: "/scd/dss/v1/uss_availability/{uss_id}"} pattern = regexp.MustCompile("^/scd/dss/v1/uss_availability/(?P[^/]*)$") - router.Routes[17] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.SetUssAvailability} + router.Routes[17] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.SetUssAvailability, Name: "scd.SetUssAvailability", Path: "/scd/dss/v1/uss_availability/{uss_id}"} return router } diff --git a/interfaces/openapi-to-go-server/example/run_example.sh b/interfaces/openapi-to-go-server/example/run_example.sh index 00161f269..4f597dea8 100755 --- a/interfaces/openapi-to-go-server/example/run_example.sh +++ b/interfaces/openapi-to-go-server/example/run_example.sh @@ -13,4 +13,4 @@ cd "${BASEDIR}" || exit docker image build -t openapi-to-go-server-demo . || exit echo "Running server..." -docker container run -it -p 8080:8080 openapi-to-go-server-demo +docker container run -it -p 8180:8080 openapi-to-go-server-demo diff --git a/interfaces/openapi-to-go-server/generate.py b/interfaces/openapi-to-go-server/generate.py index 3e08990e2..5e7ec4ffa 100644 --- a/interfaces/openapi-to-go-server/generate.py +++ b/interfaces/openapi-to-go-server/generate.py @@ -103,7 +103,15 @@ def _generate_apis( routes, new_imports = rendering.routes(api, api_package, ensure_500) server_template_vars = { "": api.package, - "": rendering.imports(list(new_imports) + [api_import]), + "": rendering.imports( + list(new_imports) + + [ + api_import, + "fmt", + "go.opentelemetry.io/otel", + "go.opentelemetry.io/otel/trace", + ] + ), "": api_package, "": "\n".join(routes), "": "\n".join(rendering.routing(api, api_package)), diff --git a/interfaces/openapi-to-go-server/rendering.py b/interfaces/openapi-to-go-server/rendering.py index a85e10fd8..d4ce4379f 100644 --- a/interfaces/openapi-to-go-server/rendering.py +++ b/interfaces/openapi-to-go-server/rendering.py @@ -458,8 +458,17 @@ def routing(api: apis.API, api_package: str) -> List[str]: ) ) lines.append( - "router.Routes[%d] = &%s.Route{Method: %s, Pattern: pattern, Handler: router.%s}" - % (i, api_package, operation.verb_const_name, operation.interface_name) + 'router.Routes[%d] = &%s.Route{Method: %s, Pattern: pattern, Handler: router.%s, Name: "%s.%s", Path: "%s%s"}' + % ( + i, + api_package, + operation.verb_const_name, + operation.interface_name, + api.package, + operation.interface_name, + prefix, + operation.path, + ) ) lines.append("") first_assignment = False diff --git a/interfaces/openapi-to-go-server/templates/common.go.template b/interfaces/openapi-to-go-server/templates/common.go.template index ca5dd0102..356337a2f 100644 --- a/interfaces/openapi-to-go-server/templates/common.go.template +++ b/interfaces/openapi-to-go-server/templates/common.go.template @@ -59,6 +59,8 @@ type Route struct { Method string Pattern *regexp.Regexp Handler Handler + Name string + Path string } type PartialRouter interface { diff --git a/interfaces/openapi-to-go-server/templates/server.go.template b/interfaces/openapi-to-go-server/templates/server.go.template index f57ca91c0..8d8baffa9 100644 --- a/interfaces/openapi-to-go-server/templates/server.go.template +++ b/interfaces/openapi-to-go-server/templates/server.go.template @@ -8,10 +8,24 @@ type APIRouter struct { Authorizer .Authorizer } +var tracer = otel.Tracer(".") + // *.APIRouter (type defined above) implements the .PartialRouter interface func (s *APIRouter) Handle(w http.ResponseWriter, r *http.Request) bool { for _, route := range s.Routes { if route.Method == r.Method && route.Pattern.MatchString(r.URL.Path) { + + // We retrieve the current span from the otelhttp handler to set its name property. + span := trace.SpanFromContext(r.Context()) + + if span.IsRecording() { // If the span is not recording, the name cannot be changed. This also likely means the otelhttp handler is not present (tracing disabled). + span.SetName(fmt.Sprintf("%s %s", r.Method, route.Path)) + } + + ctx, span := tracer.Start(r.Context(), route.Name) + defer span.End() + r = r.WithContext(ctx) + route.Handler(route.Pattern, w, r) return true } diff --git a/pkg/api/auxv1/server.gen.go b/pkg/api/auxv1/server.gen.go index bc5e3682a..701dab79a 100644 --- a/pkg/api/auxv1/server.gen.go +++ b/pkg/api/auxv1/server.gen.go @@ -3,7 +3,10 @@ package auxv1 import ( "context" + "fmt" "github.com/interuss/dss/pkg/api" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" "net/http" "regexp" ) @@ -14,10 +17,24 @@ type APIRouter struct { Authorizer api.Authorizer } +var tracer = otel.Tracer("auxv1.api") + // *auxv1.APIRouter (type defined above) implements the api.PartialRouter interface func (s *APIRouter) Handle(w http.ResponseWriter, r *http.Request) bool { for _, route := range s.Routes { if route.Method == r.Method && route.Pattern.MatchString(r.URL.Path) { + + // We retrieve the current span from the otelhttp handler to set its name property. + span := trace.SpanFromContext(r.Context()) + + if span.IsRecording() { // If the span is not recording, the name cannot be changed. This also likely means the otelhttp handler is not present (tracing disabled). + span.SetName(fmt.Sprintf("%s %s", r.Method, route.Path)) + } + + ctx, span := tracer.Start(r.Context(), route.Name) + defer span.End() + r = r.WithContext(ctx) + route.Handler(route.Pattern, w, r) return true } @@ -295,28 +312,28 @@ func MakeAPIRouter(impl Implementation, auth api.Authorizer) APIRouter { router := APIRouter{Implementation: impl, Authorizer: auth, Routes: make([]*api.Route, 8)} pattern := regexp.MustCompile("^/aux/v1/version$") - router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetVersion} + router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetVersion, Name: "auxv1.GetVersion", Path: "/aux/v1/version"} pattern = regexp.MustCompile("^/aux/v1/validate_oauth$") - router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.ValidateOauth} + router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.ValidateOauth, Name: "auxv1.ValidateOauth", Path: "/aux/v1/validate_oauth"} pattern = regexp.MustCompile("^/aux/v1/pool$") - router.Routes[2] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetPool} + router.Routes[2] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetPool, Name: "auxv1.GetPool", Path: "/aux/v1/pool"} pattern = regexp.MustCompile("^/aux/v1/pool/dss_instances$") - router.Routes[3] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetDSSInstances} + router.Routes[3] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetDSSInstances, Name: "auxv1.GetDSSInstances", Path: "/aux/v1/pool/dss_instances"} pattern = regexp.MustCompile("^/aux/v1/pool/dss_instances/heartbeat$") - router.Routes[4] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.PutDSSInstancesHeartbeat} + router.Routes[4] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.PutDSSInstancesHeartbeat, Name: "auxv1.PutDSSInstancesHeartbeat", Path: "/aux/v1/pool/dss_instances/heartbeat"} pattern = regexp.MustCompile("^/aux/v1/configuration/accepted_ca_certs$") - router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetAcceptedCAs} + router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetAcceptedCAs, Name: "auxv1.GetAcceptedCAs", Path: "/aux/v1/configuration/accepted_ca_certs"} pattern = regexp.MustCompile("^/aux/v1/configuration/ca_certs$") - router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetInstanceCAs} + router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetInstanceCAs, Name: "auxv1.GetInstanceCAs", Path: "/aux/v1/configuration/ca_certs"} pattern = regexp.MustCompile("^/aux/v1/configuration/scd_lock_mode$") - router.Routes[7] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetScdLockMode} + router.Routes[7] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetScdLockMode, Name: "auxv1.GetScdLockMode", Path: "/aux/v1/configuration/scd_lock_mode"} return router } diff --git a/pkg/api/common.gen.go b/pkg/api/common.gen.go index 9e0183eda..2512a0dbb 100644 --- a/pkg/api/common.gen.go +++ b/pkg/api/common.gen.go @@ -62,6 +62,8 @@ type Route struct { Method string Pattern *regexp.Regexp Handler Handler + Name string + Path string } type PartialRouter interface { diff --git a/pkg/api/ridv1/server.gen.go b/pkg/api/ridv1/server.gen.go index 67eba7ce8..b288c3edd 100644 --- a/pkg/api/ridv1/server.gen.go +++ b/pkg/api/ridv1/server.gen.go @@ -4,7 +4,10 @@ package ridv1 import ( "context" "encoding/json" + "fmt" "github.com/interuss/dss/pkg/api" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" "net/http" "regexp" ) @@ -15,10 +18,24 @@ type APIRouter struct { Authorizer api.Authorizer } +var tracer = otel.Tracer("ridv1.api") + // *ridv1.APIRouter (type defined above) implements the api.PartialRouter interface func (s *APIRouter) Handle(w http.ResponseWriter, r *http.Request) bool { for _, route := range s.Routes { if route.Method == r.Method && route.Pattern.MatchString(r.URL.Path) { + + // We retrieve the current span from the otelhttp handler to set its name property. + span := trace.SpanFromContext(r.Context()) + + if span.IsRecording() { // If the span is not recording, the name cannot be changed. This also likely means the otelhttp handler is not present (tracing disabled). + span.SetName(fmt.Sprintf("%s %s", r.Method, route.Path)) + } + + ctx, span := tracer.Start(r.Context(), route.Name) + defer span.End() + r = r.WithContext(ctx) + route.Handler(route.Pattern, w, r) return true } @@ -522,34 +539,34 @@ func MakeAPIRouter(impl Implementation, auth api.Authorizer) APIRouter { router := APIRouter{Implementation: impl, Authorizer: auth, Routes: make([]*api.Route, 10)} pattern := regexp.MustCompile("^/v1/dss/identification_service_areas$") - router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchIdentificationServiceAreas} + router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchIdentificationServiceAreas, Name: "ridv1.SearchIdentificationServiceAreas", Path: "/v1/dss/identification_service_areas"} pattern = regexp.MustCompile("^/v1/dss/identification_service_areas/(?P[^/]*)$") - router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetIdentificationServiceArea} + router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetIdentificationServiceArea, Name: "ridv1.GetIdentificationServiceArea", Path: "/v1/dss/identification_service_areas/{id}"} pattern = regexp.MustCompile("^/v1/dss/identification_service_areas/(?P[^/]*)$") - router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateIdentificationServiceArea} + router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateIdentificationServiceArea, Name: "ridv1.CreateIdentificationServiceArea", Path: "/v1/dss/identification_service_areas/{id}"} pattern = regexp.MustCompile("^/v1/dss/identification_service_areas/(?P[^/]*)/(?P[^/]*)$") - router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateIdentificationServiceArea} + router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateIdentificationServiceArea, Name: "ridv1.UpdateIdentificationServiceArea", Path: "/v1/dss/identification_service_areas/{id}/{version}"} pattern = regexp.MustCompile("^/v1/dss/identification_service_areas/(?P[^/]*)/(?P[^/]*)$") - router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteIdentificationServiceArea} + router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteIdentificationServiceArea, Name: "ridv1.DeleteIdentificationServiceArea", Path: "/v1/dss/identification_service_areas/{id}/{version}"} pattern = regexp.MustCompile("^/v1/dss/subscriptions$") - router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchSubscriptions} + router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchSubscriptions, Name: "ridv1.SearchSubscriptions", Path: "/v1/dss/subscriptions"} pattern = regexp.MustCompile("^/v1/dss/subscriptions/(?P[^/]*)$") - router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription} + router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription, Name: "ridv1.GetSubscription", Path: "/v1/dss/subscriptions/{id}"} pattern = regexp.MustCompile("^/v1/dss/subscriptions/(?P[^/]*)$") - router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription} + router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription, Name: "ridv1.CreateSubscription", Path: "/v1/dss/subscriptions/{id}"} pattern = regexp.MustCompile("^/v1/dss/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription} + router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription, Name: "ridv1.UpdateSubscription", Path: "/v1/dss/subscriptions/{id}/{version}"} pattern = regexp.MustCompile("^/v1/dss/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription} + router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription, Name: "ridv1.DeleteSubscription", Path: "/v1/dss/subscriptions/{id}/{version}"} return router } diff --git a/pkg/api/ridv2/server.gen.go b/pkg/api/ridv2/server.gen.go index 842762bf4..d238a2cf5 100644 --- a/pkg/api/ridv2/server.gen.go +++ b/pkg/api/ridv2/server.gen.go @@ -4,7 +4,10 @@ package ridv2 import ( "context" "encoding/json" + "fmt" "github.com/interuss/dss/pkg/api" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" "net/http" "regexp" ) @@ -15,10 +18,24 @@ type APIRouter struct { Authorizer api.Authorizer } +var tracer = otel.Tracer("ridv2.api") + // *ridv2.APIRouter (type defined above) implements the api.PartialRouter interface func (s *APIRouter) Handle(w http.ResponseWriter, r *http.Request) bool { for _, route := range s.Routes { if route.Method == r.Method && route.Pattern.MatchString(r.URL.Path) { + + // We retrieve the current span from the otelhttp handler to set its name property. + span := trace.SpanFromContext(r.Context()) + + if span.IsRecording() { // If the span is not recording, the name cannot be changed. This also likely means the otelhttp handler is not present (tracing disabled). + span.SetName(fmt.Sprintf("%s %s", r.Method, route.Path)) + } + + ctx, span := tracer.Start(r.Context(), route.Name) + defer span.End() + r = r.WithContext(ctx) + route.Handler(route.Pattern, w, r) return true } @@ -522,34 +539,34 @@ func MakeAPIRouter(impl Implementation, auth api.Authorizer) APIRouter { router := APIRouter{Implementation: impl, Authorizer: auth, Routes: make([]*api.Route, 10)} pattern := regexp.MustCompile("^/rid/v2/dss/identification_service_areas$") - router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchIdentificationServiceAreas} + router.Routes[0] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchIdentificationServiceAreas, Name: "ridv2.SearchIdentificationServiceAreas", Path: "/rid/v2/dss/identification_service_areas"} pattern = regexp.MustCompile("^/rid/v2/dss/identification_service_areas/(?P[^/]*)$") - router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetIdentificationServiceArea} + router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetIdentificationServiceArea, Name: "ridv2.GetIdentificationServiceArea", Path: "/rid/v2/dss/identification_service_areas/{id}"} pattern = regexp.MustCompile("^/rid/v2/dss/identification_service_areas/(?P[^/]*)$") - router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateIdentificationServiceArea} + router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateIdentificationServiceArea, Name: "ridv2.CreateIdentificationServiceArea", Path: "/rid/v2/dss/identification_service_areas/{id}"} pattern = regexp.MustCompile("^/rid/v2/dss/identification_service_areas/(?P[^/]*)/(?P[^/]*)$") - router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateIdentificationServiceArea} + router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateIdentificationServiceArea, Name: "ridv2.UpdateIdentificationServiceArea", Path: "/rid/v2/dss/identification_service_areas/{id}/{version}"} pattern = regexp.MustCompile("^/rid/v2/dss/identification_service_areas/(?P[^/]*)/(?P[^/]*)$") - router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteIdentificationServiceArea} + router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteIdentificationServiceArea, Name: "ridv2.DeleteIdentificationServiceArea", Path: "/rid/v2/dss/identification_service_areas/{id}/{version}"} pattern = regexp.MustCompile("^/rid/v2/dss/subscriptions$") - router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchSubscriptions} + router.Routes[5] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.SearchSubscriptions, Name: "ridv2.SearchSubscriptions", Path: "/rid/v2/dss/subscriptions"} pattern = regexp.MustCompile("^/rid/v2/dss/subscriptions/(?P[^/]*)$") - router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription} + router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription, Name: "ridv2.GetSubscription", Path: "/rid/v2/dss/subscriptions/{id}"} pattern = regexp.MustCompile("^/rid/v2/dss/subscriptions/(?P[^/]*)$") - router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription} + router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription, Name: "ridv2.CreateSubscription", Path: "/rid/v2/dss/subscriptions/{id}"} pattern = regexp.MustCompile("^/rid/v2/dss/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription} + router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription, Name: "ridv2.UpdateSubscription", Path: "/rid/v2/dss/subscriptions/{id}/{version}"} pattern = regexp.MustCompile("^/rid/v2/dss/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription} + router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription, Name: "ridv2.DeleteSubscription", Path: "/rid/v2/dss/subscriptions/{id}/{version}"} return router } diff --git a/pkg/api/scdv1/server.gen.go b/pkg/api/scdv1/server.gen.go index aa665fd9c..701f3b6ff 100644 --- a/pkg/api/scdv1/server.gen.go +++ b/pkg/api/scdv1/server.gen.go @@ -4,7 +4,10 @@ package scdv1 import ( "context" "encoding/json" + "fmt" "github.com/interuss/dss/pkg/api" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" "net/http" "regexp" ) @@ -15,10 +18,24 @@ type APIRouter struct { Authorizer api.Authorizer } +var tracer = otel.Tracer("scdv1.api") + // *scdv1.APIRouter (type defined above) implements the api.PartialRouter interface func (s *APIRouter) Handle(w http.ResponseWriter, r *http.Request) bool { for _, route := range s.Routes { if route.Method == r.Method && route.Pattern.MatchString(r.URL.Path) { + + // We retrieve the current span from the otelhttp handler to set its name property. + span := trace.SpanFromContext(r.Context()) + + if span.IsRecording() { // If the span is not recording, the name cannot be changed. This also likely means the otelhttp handler is not present (tracing disabled). + span.SetName(fmt.Sprintf("%s %s", r.Method, route.Path)) + } + + ctx, span := tracer.Start(r.Context(), route.Name) + defer span.End() + r = r.WithContext(ctx) + route.Handler(route.Pattern, w, r) return true } @@ -953,58 +970,58 @@ func MakeAPIRouter(impl Implementation, auth api.Authorizer) APIRouter { router := APIRouter{Implementation: impl, Authorizer: auth, Routes: make([]*api.Route, 18)} pattern := regexp.MustCompile("^/dss/v1/operational_intent_references/query$") - router.Routes[0] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryOperationalIntentReferences} + router.Routes[0] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryOperationalIntentReferences, Name: "scdv1.QueryOperationalIntentReferences", Path: "/dss/v1/operational_intent_references/query"} pattern = regexp.MustCompile("^/dss/v1/operational_intent_references/(?P[^/]*)$") - router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetOperationalIntentReference} + router.Routes[1] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetOperationalIntentReference, Name: "scdv1.GetOperationalIntentReference", Path: "/dss/v1/operational_intent_references/{entityid}"} pattern = regexp.MustCompile("^/dss/v1/operational_intent_references/(?P[^/]*)$") - router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateOperationalIntentReference} + router.Routes[2] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateOperationalIntentReference, Name: "scdv1.CreateOperationalIntentReference", Path: "/dss/v1/operational_intent_references/{entityid}"} pattern = regexp.MustCompile("^/dss/v1/operational_intent_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateOperationalIntentReference} + router.Routes[3] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateOperationalIntentReference, Name: "scdv1.UpdateOperationalIntentReference", Path: "/dss/v1/operational_intent_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/dss/v1/operational_intent_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteOperationalIntentReference} + router.Routes[4] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteOperationalIntentReference, Name: "scdv1.DeleteOperationalIntentReference", Path: "/dss/v1/operational_intent_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/dss/v1/constraint_references/query$") - router.Routes[5] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryConstraintReferences} + router.Routes[5] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QueryConstraintReferences, Name: "scdv1.QueryConstraintReferences", Path: "/dss/v1/constraint_references/query"} pattern = regexp.MustCompile("^/dss/v1/constraint_references/(?P[^/]*)$") - router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetConstraintReference} + router.Routes[6] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetConstraintReference, Name: "scdv1.GetConstraintReference", Path: "/dss/v1/constraint_references/{entityid}"} pattern = regexp.MustCompile("^/dss/v1/constraint_references/(?P[^/]*)$") - router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateConstraintReference} + router.Routes[7] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateConstraintReference, Name: "scdv1.CreateConstraintReference", Path: "/dss/v1/constraint_references/{entityid}"} pattern = regexp.MustCompile("^/dss/v1/constraint_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateConstraintReference} + router.Routes[8] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateConstraintReference, Name: "scdv1.UpdateConstraintReference", Path: "/dss/v1/constraint_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/dss/v1/constraint_references/(?P[^/]*)/(?P[^/]*)$") - router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteConstraintReference} + router.Routes[9] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteConstraintReference, Name: "scdv1.DeleteConstraintReference", Path: "/dss/v1/constraint_references/{entityid}/{ovn}"} pattern = regexp.MustCompile("^/dss/v1/subscriptions/query$") - router.Routes[10] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QuerySubscriptions} + router.Routes[10] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.QuerySubscriptions, Name: "scdv1.QuerySubscriptions", Path: "/dss/v1/subscriptions/query"} pattern = regexp.MustCompile("^/dss/v1/subscriptions/(?P[^/]*)$") - router.Routes[11] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription} + router.Routes[11] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetSubscription, Name: "scdv1.GetSubscription", Path: "/dss/v1/subscriptions/{subscriptionid}"} pattern = regexp.MustCompile("^/dss/v1/subscriptions/(?P[^/]*)$") - router.Routes[12] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription} + router.Routes[12] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.CreateSubscription, Name: "scdv1.CreateSubscription", Path: "/dss/v1/subscriptions/{subscriptionid}"} pattern = regexp.MustCompile("^/dss/v1/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[13] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription} + router.Routes[13] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.UpdateSubscription, Name: "scdv1.UpdateSubscription", Path: "/dss/v1/subscriptions/{subscriptionid}/{version}"} pattern = regexp.MustCompile("^/dss/v1/subscriptions/(?P[^/]*)/(?P[^/]*)$") - router.Routes[14] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription} + router.Routes[14] = &api.Route{Method: http.MethodDelete, Pattern: pattern, Handler: router.DeleteSubscription, Name: "scdv1.DeleteSubscription", Path: "/dss/v1/subscriptions/{subscriptionid}/{version}"} pattern = regexp.MustCompile("^/dss/v1/reports$") - router.Routes[15] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.MakeDssReport} + router.Routes[15] = &api.Route{Method: http.MethodPost, Pattern: pattern, Handler: router.MakeDssReport, Name: "scdv1.MakeDssReport", Path: "/dss/v1/reports"} pattern = regexp.MustCompile("^/dss/v1/uss_availability/(?P[^/]*)$") - router.Routes[16] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetUssAvailability} + router.Routes[16] = &api.Route{Method: http.MethodGet, Pattern: pattern, Handler: router.GetUssAvailability, Name: "scdv1.GetUssAvailability", Path: "/dss/v1/uss_availability/{uss_id}"} pattern = regexp.MustCompile("^/dss/v1/uss_availability/(?P[^/]*)$") - router.Routes[17] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.SetUssAvailability} + router.Routes[17] = &api.Route{Method: http.MethodPut, Pattern: pattern, Handler: router.SetUssAvailability, Name: "scdv1.SetUssAvailability", Path: "/dss/v1/uss_availability/{uss_id}"} return router }