diff --git a/adapters/http-base/src/main/java/org/eclipse/hono/adapter/http/AbstractVertxBasedHttpProtocolAdapter.java b/adapters/http-base/src/main/java/org/eclipse/hono/adapter/http/AbstractVertxBasedHttpProtocolAdapter.java index cce37666e2..3e03651474 100644 --- a/adapters/http-base/src/main/java/org/eclipse/hono/adapter/http/AbstractVertxBasedHttpProtocolAdapter.java +++ b/adapters/http-base/src/main/java/org/eclipse/hono/adapter/http/AbstractVertxBasedHttpProtocolAdapter.java @@ -84,6 +84,9 @@ public abstract class AbstractVertxBasedHttpProtocolAdapter - * This method creates a router instance along with a route matching all request. That route is initialized with the - * following handlers and failure handlers: + * This method creates a router instance along with a route matching all requests. The handler set + * on that route makes sure that *
    - *
  1. a default failure handler,
  2. - *
  3. a handler to keep track of the tracing span created for the request by means of the Vert.x/Quarkus - * instrumentation,
  4. - *
  5. a handler to add a Micrometer {@code Timer.Sample} to the routing context,
  6. - *
  7. a handler to log when the connection is closed prematurely,
  8. + *
  9. the tracing span created for the request by means of the Vert.x/Quarkus + * instrumentation is available via {@link HttpServerSpanHelper#serverSpan(RoutingContext)},
  10. + *
  11. a Micrometer {@code Timer.Sample} is added to the routing context,
  12. + *
  13. there is log output when the connection is closed prematurely.
  14. *
+ * Also a default failure handler is set. * * @return The newly created router (never {@code null}). */ protected Router createRouter() { - // route (failure) handlers are added in a specific order here! final Router router = Router.router(vertx); - final Route matchAllFailuresRoute = router.route(); - // failure handler is added on a separate route for which no name is set, otherwise all tracing spans - // of failed HTTP requests would get that route name as span name - matchAllFailuresRoute.failureHandler(new DefaultFailureHandler()); + final var customTags = getCustomTags(); + final DefaultFailureHandler defaultFailureHandler = new DefaultFailureHandler(); final Route matchAllRoute = router.route(); - // route name will be used as HTTP request tracing span name, - // ensuring a fixed name is set in case no other route matches (otherwise the span name would unsuitably be set to the request path) - matchAllRoute.setName("/* (default route)"); - // 1. handler to keep track of the tracing span created by the Vert.x/Quarkus instrumentation (set as active span there) - matchAllRoute.handler(HttpServerSpanHelper.getRouteHandlerForAdoptingActiveSpan(tracer, getCustomTags())); - - // 2. handler to start the metrics timer - matchAllRoute.handler(ctx -> { - ctx.put(KEY_MICROMETER_SAMPLE, getMetrics().startTimer()); - ctx.next(); + matchAllRoute.failureHandler(ctx -> { + if (ctx.get(KEY_MATCH_ALL_ROUTE_APPLIED) == null) { + // handler of matchAllRoute not applied, meaning this request is invalid/failed from the start; + // ensure span name is set to fixed string instead of the request path + ctx.request().routed(MATCH_ALL_ROUTE_NAME); + HttpServerSpanHelper.adoptActiveSpanIntoContext(tracer, customTags, ctx); + } + defaultFailureHandler.handle(ctx); }); - - // 3. handler to log when the connection is closed prematurely matchAllRoute.handler(ctx -> { + // ensure span name is set to fixed string instead of the request path + ctx.request().routed(MATCH_ALL_ROUTE_NAME); + ctx.put(KEY_MATCH_ALL_ROUTE_APPLIED, true); + // keep track of the tracing span created by the Vert.x/Quarkus instrumentation (set as active span there) + HttpServerSpanHelper.adoptActiveSpanIntoContext(tracer, customTags, ctx); + // start the metrics timer + ctx.put(KEY_MICROMETER_SAMPLE, getMetrics().startTimer()); + // log when the connection is closed prematurely if (!ctx.response().closed() && !ctx.response().ended()) { ctx.response().closeHandler(v -> logResponseGettingClosedPrematurely(ctx)); } diff --git a/service-base/src/main/java/org/eclipse/hono/service/http/HttpServerSpanHelper.java b/service-base/src/main/java/org/eclipse/hono/service/http/HttpServerSpanHelper.java index 9edad6d797..9bd3abdcfe 100644 --- a/service-base/src/main/java/org/eclipse/hono/service/http/HttpServerSpanHelper.java +++ b/service-base/src/main/java/org/eclipse/hono/service/http/HttpServerSpanHelper.java @@ -23,7 +23,6 @@ import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; -import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; /** @@ -42,33 +41,31 @@ private HttpServerSpanHelper() { } /** - * Gets a route handler for getting the active span created for an HTTP request and storing it in the routing - * context, so that it is available via {@link #serverSpan(RoutingContext)}. Also applies the given tags on the - * active span. + * Gets the active span created for an HTTP request and stores it in the routing context, so that it is available + * via {@link #serverSpan(RoutingContext)}. Also applies the given tags on the active span. * * @param tracer The tracer instance. * @param customTags The custom tags to apply to the active span. - * @return The handler. + * @param routingContext The routing context to set the span in. * @throws NullPointerException if any of the parameters is {@code null}. */ - public static Handler getRouteHandlerForAdoptingActiveSpan( + public static void adoptActiveSpanIntoContext( final Tracer tracer, - final Map customTags) { + final Map customTags, + final RoutingContext routingContext) { Objects.requireNonNull(tracer); Objects.requireNonNull(customTags); - return routingContext -> { - if (routingContext.get(ROUTING_CONTEXT_SPAN_KEY) == null) { - Optional.ofNullable(tracer.activeSpan()).ifPresentOrElse( - span -> { - customTags.forEach(span::setTag); - routingContext.put(ROUTING_CONTEXT_SPAN_KEY, span); - }, - () -> LOG.warn("no active span set")); + Objects.requireNonNull(routingContext); - } - routingContext.next(); - }; + if (routingContext.get(ROUTING_CONTEXT_SPAN_KEY) == null) { + Optional.ofNullable(tracer.activeSpan()).ifPresentOrElse( + span -> { + customTags.forEach(span::setTag); + routingContext.put(ROUTING_CONTEXT_SPAN_KEY, span); + }, + () -> LOG.warn("no active span set")); + } } /** diff --git a/service-base/src/main/java/org/eclipse/hono/service/http/HttpServiceBase.java b/service-base/src/main/java/org/eclipse/hono/service/http/HttpServiceBase.java index dc20780aed..9f39202ccc 100644 --- a/service-base/src/main/java/org/eclipse/hono/service/http/HttpServiceBase.java +++ b/service-base/src/main/java/org/eclipse/hono/service/http/HttpServiceBase.java @@ -42,6 +42,10 @@ */ public abstract class HttpServiceBase extends AbstractServiceBase { + private static final String MATCH_ALL_ROUTE_NAME = "/* (default route)"; + + private static final String KEY_MATCH_ALL_ROUTE_APPLIED = "matchAllRouteApplied"; + private final Map endpoints = new HashMap<>(); private HttpServer server; @@ -168,33 +172,40 @@ protected Future onStartupSuccess() { /** * Creates the router for handling requests. *

- * This method creates a router instance along with a route matching all request. That route is initialized with the - * following handlers and failure handlers: + * This method creates a router instance along with routes matching all request. The following handlers get applied: *

    - *
  • a default failure handler,
  • *
  • a handler to keep track of the tracing span created for the request by means of the Vert.x/Quarkus * instrumentation,
  • *
  • the authentication handler, set via {@link #setAuthHandler(AuthenticationHandler)}.
  • *
+ * Also a default failure handler is set. * * @return The newly created router (never {@code null}). */ protected Router createRouter() { - // route (failure) handlers are added in a specific order here! final Router router = Router.router(vertx); - final Route matchAllFailuresRoute = router.route(); - // failure handler is added on a separate route for which no name is set, otherwise all tracing spans - // of failed HTTP requests would get that route name as span name - matchAllFailuresRoute.failureHandler(new DefaultFailureHandler()); + final var customTags = getCustomTags(); + final DefaultFailureHandler defaultFailureHandler = new DefaultFailureHandler(); final Route matchAllRoute = router.route(); - // route name will be used as HTTP request tracing span name, - // ensuring a fixed name is set in case no other route matches (otherwise the span name would unsuitably be set to the request path) - matchAllRoute.setName("/* (default route)"); - // handler to keep track of the tracing span created by the Vert.x/Quarkus instrumentation (set as active span there) - matchAllRoute.handler(HttpServerSpanHelper.getRouteHandlerForAdoptingActiveSpan(tracer, getCustomTags())); - // AuthHandler + matchAllRoute.failureHandler(ctx -> { + if (ctx.get(KEY_MATCH_ALL_ROUTE_APPLIED) == null) { + // handler of matchAllRoute not applied, meaning this request is invalid/failed from the start; + // ensure span name is set to fixed string instead of the request path + ctx.request().routed(MATCH_ALL_ROUTE_NAME); + HttpServerSpanHelper.adoptActiveSpanIntoContext(tracer, customTags, ctx); + } + defaultFailureHandler.handle(ctx); + }); + matchAllRoute.handler(ctx -> { + // ensure span name is set to fixed string instead of the request path + ctx.request().routed(MATCH_ALL_ROUTE_NAME); + ctx.put(KEY_MATCH_ALL_ROUTE_APPLIED, true); + // keep track of the tracing span created by the Vert.x/Quarkus instrumentation (set as active span there) + HttpServerSpanHelper.adoptActiveSpanIntoContext(tracer, customTags, ctx); + ctx.next(); + }); addAuthHandler(router); return router; }