Repository: quarkusio/quarkus
Issue: OpenTelemetry: High span name cardinality for invalid HTTP request spans

### Describe the bug

This is about the remaining issue from #26216:
When using the `quarkus-opentelemetry` extension and observing Vert.x HTTP server request spans, the span names for **invalid HTTP requests** (resulting in status 400 or also 501 responses) contain the full request URI path. The [OTEL spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#name) declares such high cardinality span names as unsuitable. 

In practice, this means the span selection combobox in the Jaeger UI gets fill with all kinds of weird URI paths of bot requests trying to exploit some vulnerability.
```
/someWeirdPathTryingToExploitSomeVulnerability?someParamX
```

_Some_ of these span names still can get renamed by using a "match-all" Vert.x route with a failure handler (invoking `ctx.request().routed(name)` there), 

But there are kinds of invalid HTTP requests, for which no route failure handler will get invoked. This happens for example with HTTP requests with an invalid `Content-Length` header value.

### Expected behavior

I would expect some fixed span name (e.g. the HTTP request method name) to be used as span name for such invalid HTTP requests - **if** no request route name got set/applied (i.e. no named route got matched and `ctx.request().routed(name)` wasn't invoked).


### Actual behavior

High cardinality span names are used.

### How to Reproduce?

Make invalid HTTP requests to a quarkus-opentelemetry application having a Vert.x HTTP server endpoint and observe created span names.
Examples:
`printf 'GET invalid__no_leading_slash HTTP/1.0\\r\\n\\r\\n' | nc -q 3 localhost 80`
`printf 'GET /something%%%%3 HTTP/1.0\\r\\n\\r\\n' | nc -q 3 localhost 80`

`printf 'GET /something HTTP/1.1\\r\\nContent-Length: 18446744073709551615\\r\\n\\r\\n' | nc -q 3 localhost 80`
=> no Vert.x route getting invoked

`printf 'GET /something HTTP/5.0\\r\\n\\r\\n' | nc -q 3 localhost 80`
=> this actually returns status 501; no Vert.x route getting invoked

### Output of `uname -a` or `ver`

_No response_

### Output of `java -version`

openjdk 17.0.3 2022-04-19

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

2.10.2

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

_No response_

### Additional information

_No response_

Changed files:
extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerUtil.java
extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java
extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryDevModeTest.java
extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/HelloResource.java
extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java
extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropNamesSampler.java

diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/HelloResource.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/HelloResource.java
index 0e9fc7e0722..7d12639ffc5 100644
--- a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/HelloResource.java
+++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/HelloResource.java
@@ -11,6 +11,7 @@ public class HelloResource {
 
     @GET
     public String get() {
+        // The span name is not updated with the route yet.
         return ((ReadableSpan) Span.current()).getName();
     }
 }
diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryDevModeTest.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryDevModeTest.java
index 80066dd997d..4ffca2350f3 100644
--- a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryDevModeTest.java
+++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryDevModeTest.java
@@ -23,7 +23,7 @@ void testDevMode() {
         //and the hot replacement stuff is not messing things up
         RestAssured.when().get("/hello").then()
                 .statusCode(200)
-                .body(is("/hello"));
+                .body(is("HTTP GET"));
 
         RestAssured.when().get("/tracer").then()
                 .statusCode(200)
diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropNamesSampler.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSampler.java
similarity index 63%
rename from extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropNamesSampler.java
rename to extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSampler.java
index e0418cfbdc1..53966c53032 100644
--- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropNamesSampler.java
+++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSampler.java
@@ -8,14 +8,15 @@
 import io.opentelemetry.sdk.trace.data.LinkData;
 import io.opentelemetry.sdk.trace.samplers.Sampler;
 import io.opentelemetry.sdk.trace.samplers.SamplingResult;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
 
-public class DropNamesSampler implements Sampler {
+public class DropTargetsSampler implements Sampler {
     private final Sampler sampler;
-    private final List<String> dropNames;
+    private final List<String> dropTargets;
 
-    public DropNamesSampler(Sampler sampler, List<String> dropNames) {
+    public DropTargetsSampler(Sampler sampler, List<String> dropTargets) {
         this.sampler = sampler;
-        this.dropNames = dropNames;
+        this.dropTargets = dropTargets;
     }
 
     @Override
@@ -23,10 +24,10 @@ public SamplingResult shouldSample(Context parentContext, String traceId, String
             Attributes attributes, List<LinkData> parentLinks) {
 
         if (spanKind.equals(SpanKind.SERVER)) {
-            for (String dropName : dropNames) {
-                if (name.startsWith(dropName)) {
-                    return SamplingResult.drop();
-                }
+            String target = attributes.get(SemanticAttributes.HTTP_TARGET);
+            // TODO - radcortez - Match /* endpoints
+            if (target != null && dropTargets.contains(target)) {
+                return SamplingResult.drop();
             }
         }
 
diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java
index 89990890731..31ea877a544 100644
--- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java
+++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java
@@ -139,14 +139,14 @@ public void setupSampler(
             List<String> dropStaticResources) {
 
         LateBoundSampler lateBoundSampler = CDI.current().select(LateBoundSampler.class, Any.Literal.INSTANCE).get();
-        List<String> dropNames = new ArrayList<>();
+        List<String> dropTargets = new ArrayList<>();
         if (config.suppressNonApplicationUris) {
-            dropNames.addAll(dropNonApplicationUris);
+            dropTargets.addAll(dropNonApplicationUris);
         }
         if (!config.includeStaticResources) {
-            dropNames.addAll(dropStaticResources);
+            dropTargets.addAll(dropStaticResources);
         }
-        Sampler samplerBean = TracerUtil.mapSampler(config.sampler, dropNames);
+        Sampler samplerBean = TracerUtil.mapSampler(config.sampler, dropTargets);
         lateBoundSampler.setSamplerDelegate(samplerBean);
     }
 }
diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerUtil.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerUtil.java
index 632e649c87a..154dc717139 100644
--- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerUtil.java
+++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerUtil.java
@@ -38,15 +38,15 @@ private static Sampler getBaseSampler(String samplerName, Optional<Double> ratio
     }
 
     public static Sampler mapSampler(TracerRuntimeConfig.SamplerConfig samplerConfig,
-            List<String> dropNames) {
+            List<String> dropTargets) {
         Sampler sampler = CDI.current()
                 .select(Sampler.class, Any.Literal.INSTANCE)
                 .stream()
                 .filter(o -> !(o instanceof LateBoundSampler))
                 .findFirst().orElseGet(() -> getBaseSampler(samplerConfig.samplerName, samplerConfig.ratio));
 
-        if (!dropNames.isEmpty()) {
-            sampler = new DropNamesSampler(sampler, dropNames);
+        if (!dropTargets.isEmpty()) {
+            sampler = new DropTargetsSampler(sampler, dropTargets);
         }
 
         if (samplerConfig.parentBased) {
diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java
index cbc01516f96..7ce2937f708 100644
--- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java
+++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java
@@ -190,7 +190,7 @@ public String target(final HttpRequest request) {
 
         @Override
         public String route(final HttpRequest request) {
-            return request.uri().length() > 1 ? request.uri() : null;
+            return null;
         }
 
         @Override
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
index ee81cea9987..55105a03635 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
@@ -1,5 +1,6 @@
 package io.quarkus.vertx.http.deployment;
 
+import static io.quarkus.runtime.TemplateHtmlBuilder.adjustRoot;
 import static io.quarkus.vertx.http.deployment.RouteBuildItem.RouteType.FRAMEWORK_ROUTE;
 
 import java.io.IOException;
@@ -51,6 +52,7 @@
 import io.quarkus.vertx.http.deployment.devmode.HttpRemoteDevClientProvider;
 import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem;
 import io.quarkus.vertx.http.deployment.spi.FrameworkEndpointsBuildItem;
+import io.quarkus.vertx.http.runtime.BasicRoute;
 import io.quarkus.vertx.http.runtime.CurrentRequestProducer;
 import io.quarkus.vertx.http.runtime.CurrentVertxRequest;
 import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;
@@ -93,8 +95,19 @@ FrameworkEndpointsBuildItem frameworkEndpoints(NonApplicationRootPathBuildItem n
             List<RouteBuildItem> routes) {
         List<String> frameworkEndpoints = new ArrayList<>();
         for (RouteBuildItem route : routes) {
-            if (FRAMEWORK_ROUTE.equals(route.getRouteType()) && route.getConfiguredPathInfo() != null) {
-                frameworkEndpoints.add(route.getConfiguredPathInfo().getEndpointPath(nonApplicationRootPath));
+            if (FRAMEWORK_ROUTE.equals(route.getRouteType())) {
+                if (route.getConfiguredPathInfo() != null) {
+                    frameworkEndpoints.add(route.getConfiguredPathInfo().getEndpointPath(nonApplicationRootPath));
+                    continue;
+                }
+                if (route.getRouteFunction() != null && route.getRouteFunction() instanceof BasicRoute) {
+                    BasicRoute basicRoute = (BasicRoute) route.getRouteFunction();
+                    if (basicRoute.getPath() != null) {
+                        // Calling TemplateHtmlBuilder does not see very correct here, but it is the underlying API for ConfiguredPathInfo
+                        frameworkEndpoints
+                                .add(adjustRoot(nonApplicationRootPath.getNonApplicationRootPath(), basicRoute.getPath()));
+                    }
+                }
             }
         }
         return new FrameworkEndpointsBuildItem(frameworkEndpoints);