From debf3e2f798179979a0567c420fef7a8c1b004b5 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Thu, 23 Jun 2022 22:30:07 +0100 Subject: [PATCH] Always create a duplicated context in OpenTelemetry when executing client requests --- bom/application/pom.xml | 2 +- .../VertxClientOpenTelemetryTest.java | 29 +++++++++++++++++++ .../restclient/OpenTelemetryClientFilter.java | 8 +++-- .../vertx/InstrumenterVertxTracer.java | 2 +- independent-projects/bootstrap/pom.xml | 2 +- .../client/impl/ClientRequestContextImpl.java | 2 +- .../resteasy-reactive/pom.xml | 2 +- independent-projects/tools/pom.xml | 2 +- .../reactive/ReactiveResource.java | 12 ++++++++ .../reactive/ReactiveRestClient.java | 20 +++++++++++++ .../resources/application.properties | 0 .../OpenTelemetryReactiveClientTest.java | 13 --------- .../reactive/OpenTelemetryReactiveIT.java | 7 +++++ .../reactive/OpenTelemetryReactiveTest.java | 18 ++++++++++++ 14 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java rename integration-tests/opentelemetry-reactive/src/{test => main}/resources/application.properties (100%) create mode 100644 integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index b7c07aeabdf36..8b0783c94bdb6 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -39,7 +39,7 @@ 2.0 1.2 1.0 - 1.12.0 + 1.13.0 2.10.1 3.2.1 3.0.5 diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java index 1760daff376a2..e291fdbc71482 100644 --- a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java +++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java @@ -9,6 +9,7 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_TARGET; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_URL; import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.stream.Collectors.toSet; import static org.junit.jupiter.api.Assertions.assertEquals; import java.net.URI; @@ -27,6 +28,8 @@ import io.quarkus.runtime.StartupEvent; import io.quarkus.test.QuarkusUnitTest; import io.quarkus.test.common.http.TestHTTPResource; +import io.vertx.core.CompositeFuture; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.Router; @@ -114,14 +117,40 @@ void path() throws Exception { assertEquals(server.getParentSpanId(), client.getSpanId()); } + @Test + void multiple() throws Exception { + HttpResponse response = WebClient.create(vertx) + .get(uri.getPort(), uri.getHost(), "/multiple") + .putHeader("host", uri.getHost()) + .putHeader("port", uri.getPort() + "") + .send() + .toCompletionStage().toCompletableFuture() + .get(); + + assertEquals(HTTP_OK, response.statusCode()); + + List spans = spanExporter.getFinishedSpanItems(6); + assertEquals(1, spans.stream().map(SpanData::getTraceId).collect(toSet()).size()); + } + @ApplicationScoped public static class HelloRouter { @Inject Router router; + @Inject + Vertx vertx; public void register(@Observes StartupEvent ev) { router.get("/hello").handler(rc -> rc.response().end("hello")); router.get("/hello/:name").handler(rc -> rc.response().end("hello " + rc.pathParam("name"))); + router.get("/multiple").handler(rc -> { + String host = rc.request().getHeader("host"); + int port = Integer.parseInt(rc.request().getHeader("port")); + WebClient webClient = WebClient.create(vertx); + Future> one = webClient.get(port, host, "/hello/naruto").send(); + Future> two = webClient.get(port, host, "/hello/goku").send(); + CompositeFuture.join(one, two).onComplete(event -> rc.response().end()); + }); } } } diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java index e6e07d13d028d..0289b381e5e29 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java @@ -72,10 +72,14 @@ public OpenTelemetryClientFilter(final OpenTelemetry openTelemetry) { @Override public void filter(final ClientRequestContext request) { - Context parentContext = Context.current(); + io.vertx.core.Context vertxContext = getVertxContext(request); + io.opentelemetry.context.Context parentContext = QuarkusContextStorage.getContext(vertxContext); + if (parentContext == null) { + parentContext = io.opentelemetry.context.Context.current(); + } if (instrumenter.shouldStart(parentContext, request)) { Context spanContext = instrumenter.start(parentContext, request); - Scope scope = QuarkusContextStorage.INSTANCE.attach(getVertxContext(request), spanContext); + Scope scope = QuarkusContextStorage.INSTANCE.attach(vertxContext, spanContext); request.setProperty(REST_CLIENT_OTEL_SPAN_CLIENT_CONTEXT, spanContext); request.setProperty(REST_CLIENT_OTEL_SPAN_CLIENT_PARENT_CONTEXT, parentContext); request.setProperty(REST_CLIENT_OTEL_SPAN_CLIENT_SCOPE, scope); diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java index 294c020516213..272c1a83bb9fd 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java @@ -92,7 +92,7 @@ default SpanOperation sendRequest( if (instrumenter.shouldStart(parentContext, (REQ) request)) { io.opentelemetry.context.Context spanContext = instrumenter.start(parentContext, writableHeaders((REQ) request, headers)); - Context duplicatedContext = VertxContext.getOrCreateDuplicatedContext(context); + Context duplicatedContext = VertxContext.createNewDuplicatedContext(context); setContextSafe(duplicatedContext, true); Scope scope = QuarkusContextStorage.INSTANCE.attach(duplicatedContext, spanContext); return spanOperation(duplicatedContext, (REQ) request, toMultiMap(headers), spanContext, scope); diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index 487776d9a5fba..b0602868eb093 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -63,7 +63,7 @@ 1.7.36 22.1.0 2.6.0 - 1.12.0 + 1.13.0 7.4.2 0.0.9 0.1.1 diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java index faff2cfa99bf1..ee9833ab48be3 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java @@ -56,7 +56,7 @@ public ClientRequestContextImpl(RestClientRequestContext restClientRequestContex // Capture or create a duplicated context, and store it. Context current = client.vertx.getOrCreateContext(); - this.context = VertxContext.getOrCreateDuplicatedContext(current); + this.context = VertxContext.createNewDuplicatedContext(current); restClientRequestContext.properties.put(VERTX_CONTEXT_PROPERTY, context); } diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index cdcdfa8b27e38..bb405f1d6f6f7 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -55,7 +55,7 @@ 2.0.1.Final 1.1.6 1.6.0 - 1.12.0 + 1.13.0 4.3.1 4.5.1 1.0.0.Final diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index 107fe7e2db36d..16c83018a3e40 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -61,7 +61,7 @@ 999-SNAPSHOT 20 2.11.0 - 1.12.0 + 1.13.0 1.2.2 diff --git a/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java index 31b78a13405f2..a0f6bc2099bb6 100644 --- a/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java +++ b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java @@ -8,6 +8,8 @@ import javax.ws.rs.Path; import javax.ws.rs.QueryParam; +import org.eclipse.microprofile.rest.client.inject.RestClient; + import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.smallrye.mutiny.Uni; @@ -16,6 +18,9 @@ public class ReactiveResource { @Inject Tracer tracer; + @Inject + @RestClient + ReactiveRestClient client; @GET public Uni helloGet(@QueryParam("name") String name) { @@ -24,6 +29,13 @@ public Uni helloGet(@QueryParam("name") String name) { .eventually((Runnable) span::end); } + @GET + @Path("/multiple") + public Uni helloMultiple() { + return Uni.combine().all().unis(client.helloGet("Naruto"), client.helloGet("Goku")) + .combinedWith((s, s2) -> s + " and " + s2); + } + @POST public Uni helloPost(String body) { Span span = tracer.spanBuilder("helloPost").startSpan(); diff --git a/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java new file mode 100644 index 0000000000000..ac0d8deb06b43 --- /dev/null +++ b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java @@ -0,0 +1,20 @@ +package io.quarkus.it.opentelemetry.reactive; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +import io.smallrye.mutiny.Uni; + +@RegisterRestClient(configKey = "client") +@Path("/reactive") +interface ReactiveRestClient { + @GET + Uni helloGet(@QueryParam("name") String name); + + @POST + Uni helloPost(String body); +} diff --git a/integration-tests/opentelemetry-reactive/src/test/resources/application.properties b/integration-tests/opentelemetry-reactive/src/main/resources/application.properties similarity index 100% rename from integration-tests/opentelemetry-reactive/src/test/resources/application.properties rename to integration-tests/opentelemetry-reactive/src/main/resources/application.properties diff --git a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java index 6c68ee2098f2f..f130d7f116b1c 100644 --- a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java +++ b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java @@ -17,10 +17,7 @@ import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; -import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -111,16 +108,6 @@ void post() { assertEquals(HttpMethod.POST.name(), ((Map) client.get("attributes")).get(HTTP_METHOD.getKey())); } - @RegisterRestClient(configKey = "client") - @Path("/reactive") - interface ReactiveRestClient { - @GET - Uni helloGet(@QueryParam("name") String name); - - @POST - Uni helloPost(String body); - } - private static List> getSpans() { return when().get("/export").body().as(new TypeRef<>() { }); diff --git a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java new file mode 100644 index 0000000000000..2103579c81eee --- /dev/null +++ b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.opentelemetry.reactive; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class OpenTelemetryReactiveIT extends OpenTelemetryReactiveTest { +} diff --git a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java index 275288a35b1b6..277ae2fcb5101 100644 --- a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java +++ b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java @@ -3,6 +3,7 @@ import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.when; import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.stream.Collectors.toSet; import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -59,6 +60,23 @@ void post() { assertEquals(spans.get(0).get("traceId"), spans.get(1).get("traceId")); } + @Test + void multiple() { + given() + .contentType("application/json") + .when() + .get("/reactive/multiple") + .then() + .statusCode(200) + .body(equalTo("Hello Naruto and Hello Goku")); + + await().atMost(5, TimeUnit.SECONDS).until(() -> getSpans().size() == 7); + + List> spans = getSpans(); + assertEquals(7, spans.size()); + assertEquals(1, spans.stream().map(map -> map.get("traceId")).collect(toSet()).size()); + } + private static List> getSpans() { return when().get("/export").body().as(new TypeRef<>() { });