From d5e8723a81fe219d96be9dd929d8b4140ea882f0 Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Sat, 28 Dec 2024 09:49:29 -0500 Subject: [PATCH 1/9] start converting --- .../v1_7/server/RatpackServerTest.groovy | 2 +- .../v1_7/server/RatpackServerTest.java | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy index 19cb6d22e5ac..a997419d8730 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy @@ -21,7 +21,7 @@ import ratpack.test.embed.EmbeddedApp import spock.lang.Specification import spock.util.concurrent.PollingConditions -class RatpackServerTest extends Specification { +class RatpackServerTest2 extends Specification { def spanExporter = InMemorySpanExporter.create() def tracerProvider = SdkTracerProvider.builder() diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java new file mode 100644 index 000000000000..407d15dd6c44 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java @@ -0,0 +1,40 @@ +package io.opentelemetry.instrumentation.ratpack.v1_7.server; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.OpenTelemetrySdkBuilder; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; + +class RatpackServerTest { + + private static InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + private SdkTracerProvider tracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + + OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() + .setPropagators(ContextPropagators.create(W3CBaggagePropagator.getInstance())) + .setTracerProvider(tracerProvider).build(); + + RatpackServerTelemetry telemetry = RatpackServerTelemetry.create(openTelemetry); + + @AfterAll + static void cleanup() { + spanExporter.reset(); + } + + @Test + void testAddSpanOnHandlers() { + + + } + + +} From c376a56e6e25cb40fa1ee07c1a5708e02f0d3606 Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Sun, 29 Dec 2024 06:07:27 -0500 Subject: [PATCH 2/9] start converting --- .../v1_7/server/RatpackServerTest.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java index 407d15dd6c44..2e3fdad3d4ca 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java @@ -2,15 +2,24 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.OpenTelemetrySdkBuilder; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; +import ratpack.registry.Registry; +import ratpack.test.embed.EmbeddedApp; +import spock.util.concurrent.PollingConditions; + +import java.util.Map; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; class RatpackServerTest { @@ -31,10 +40,24 @@ static void cleanup() { } @Test - void testAddSpanOnHandlers() { + void testAddSpanOnHandlers() throws Exception { + EmbeddedApp app = EmbeddedApp.of( + spec -> { + spec.registry(registry -> Registry.of(regSpec -> telemetry.configureRegistry(regSpec))); + spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("hi-foo"))); + } + ); + app.test( httpClient -> { + assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); + new PollingConditions().eventually(() -> { + Map spans = spanExporter.getFinishedSpanItems().stream() + .collect(Collectors.toMap(SpanData::getName, span -> span)); + assertThat(spans).containsKey("GET /foo"); - } + }); + + } } From 5ed553e892b1440150f7e376045e4348f5df3f20 Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Mon, 30 Dec 2024 20:32:30 -0500 Subject: [PATCH 3/9] finish converting --- .../ratpack/v1_7/RatpackFunctionalTest.groovy | 45 --- .../client/InstrumentedHttpClientTest.groovy | 377 ------------------ .../RatpackServerApplicationTest.groovy | 169 -------- .../v1_7/server/RatpackServerTest.groovy | 163 -------- .../ratpack/v1_7/AbstractRatpackTest.java | 46 +++ .../ratpack/v1_7/client/BarForkService.java | 56 +++ .../ratpack/v1_7/client/BarService.java | 53 +++ .../client/InstrumentedHttpClientTest.java | 357 +++++++++++++++++ .../v1_7/server/OpenTelemetryModule.java | 76 ++++ .../ratpack/v1_7/server/RatpackApp.java | 35 ++ .../v1_7/server/RatpackFunctionalTest.java | 47 +++ .../server/RatpackServerApplicationTest.java | 109 +++++ .../v1_7/server/RatpackServerTest.java | 222 +++++++++-- 13 files changed, 961 insertions(+), 794 deletions(-) delete mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackFunctionalTest.groovy delete mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy delete mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy delete mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java create mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackFunctionalTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackFunctionalTest.groovy deleted file mode 100644 index c20bb5a3589f..000000000000 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackFunctionalTest.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.ratpack.v1_7 - -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter -import io.opentelemetry.sdk.trace.export.SpanExporter -import ratpack.guice.BindingsImposition -import ratpack.impose.ForceDevelopmentImposition -import ratpack.impose.ImpositionsSpec -import ratpack.impose.UserRegistryImposition -import ratpack.registry.Registry -import ratpack.test.MainClassApplicationUnderTest -import ratpack.test.embed.EmbeddedApp - -class RatpackFunctionalTest extends MainClassApplicationUnderTest { - - Registry registry - @Lazy - InMemorySpanExporter spanExporter = registry.get(SpanExporter) as InMemorySpanExporter - EmbeddedApp app = EmbeddedApp.of { server -> - server.handlers { chain -> - chain.get("other") { ctx -> ctx.render("hi-other") } - } - } - - RatpackFunctionalTest(Class mainClass) { - super(mainClass) - getAddress() - } - - @Override - void addImpositions(ImpositionsSpec impositions) { - impositions.add(ForceDevelopmentImposition.of(false)) - impositions.add(UserRegistryImposition.of { r -> - registry = r - registry - }) - impositions.add(BindingsImposition.of { - it.bindInstance(URI, app.address.resolve("other")) - }) - } -} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy deleted file mode 100644 index bd4f7c1a57d4..000000000000 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.ratpack.v1_7.client - -import io.opentelemetry.api.OpenTelemetry -import io.opentelemetry.api.trace.StatusCode -import io.opentelemetry.api.trace.Tracer -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator -import io.opentelemetry.context.Context -import io.opentelemetry.context.propagation.ContextPropagators -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetry -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry -import io.opentelemetry.sdk.OpenTelemetrySdk -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter -import io.opentelemetry.sdk.trace.SdkTracerProvider -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor -import io.opentelemetry.semconv.UrlAttributes -import ratpack.exec.Execution -import ratpack.exec.Promise -import ratpack.func.Action -import ratpack.guice.Guice -import ratpack.http.client.HttpClient -import ratpack.service.Service -import ratpack.service.StartEvent -import ratpack.test.embed.EmbeddedApp -import spock.lang.Specification -import spock.util.concurrent.PollingConditions - -import java.time.Duration -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.SERVER -import static io.opentelemetry.semconv.HttpAttributes.* - -class InstrumentedHttpClientTest extends Specification { - - def spanExporter = InMemorySpanExporter.create() - def tracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build() - - def openTelemetry = OpenTelemetrySdk.builder() - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setTracerProvider(tracerProvider).build() - - RatpackClientTelemetry telemetry = RatpackClientTelemetry.create(openTelemetry) - RatpackServerTelemetry serverTelemetry = RatpackServerTelemetry.create(openTelemetry) - - def cleanup() { - spanExporter.reset() - } - - def "propagate trace with http calls"() { - expect: - def otherApp = EmbeddedApp.of { spec -> - spec.registry( - Guice.registry { bindings -> - serverTelemetry.configureRegistry(bindings) - } - ) - spec.handlers { - it.get("bar") { ctx -> ctx.render("foo") } - } - } - - def app = EmbeddedApp.of { spec -> - spec.registry( - Guice.registry { bindings -> - serverTelemetry.configureRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) - } - ) - - spec.handlers { chain -> - chain.get("foo") { ctx -> - HttpClient instrumentedHttpClient = ctx.get(HttpClient) - instrumentedHttpClient.get(new URI("${otherApp.address}bar")) - .then { ctx.render("bar") } - } - } - } - - app.test { httpClient -> - assert "bar" == httpClient.get("foo").body.text - - new PollingConditions().eventually { - def spanData = spanExporter.finishedSpanItems.find { it.name == "GET /foo" } - def spanClientData = spanExporter.finishedSpanItems.find { it.name == "GET" && it.kind == CLIENT } - def spanDataApi = spanExporter.finishedSpanItems.find { it.name == "GET /bar" && it.kind == SERVER } - - spanData.traceId == spanClientData.traceId - spanData.traceId == spanDataApi.traceId - - spanData.kind == SERVER - spanClientData.kind == CLIENT - def atts = spanClientData.attributes.asMap() - atts[HTTP_ROUTE] == "/bar" - atts[HTTP_REQUEST_METHOD] == "GET" - atts[HTTP_RESPONSE_STATUS_CODE] == 200L - - def attributes = spanData.attributes.asMap() - attributes[HTTP_ROUTE] == "/foo" - attributes[UrlAttributes.URL_PATH] == "/foo" - attributes[HTTP_REQUEST_METHOD] == "GET" - attributes[HTTP_RESPONSE_STATUS_CODE] == 200L - - def attsApi = spanDataApi.attributes.asMap() - attsApi[HTTP_ROUTE] == "/bar" - attsApi[UrlAttributes.URL_PATH] == "/bar" - attsApi[HTTP_REQUEST_METHOD] == "GET" - attsApi[HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } - - def "add spans for multiple concurrent client calls"() { - expect: - def latch = new CountDownLatch(2) - - def otherApp = EmbeddedApp.of { spec -> - spec.handlers { chain -> - chain.get("foo") { ctx -> ctx.render("bar") } - chain.get("bar") { ctx -> ctx.render("foo") } - } - } - - def app = EmbeddedApp.of { spec -> - spec.registry( - Guice.registry { bindings -> - serverTelemetry.configureRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) - } - ) - - spec.handlers { chain -> - chain.get("path-name") { ctx -> - ctx.render("hello") - def instrumentedHttpClient = ctx.get(HttpClient) - instrumentedHttpClient.get(new URI("${otherApp.address}foo")).then { latch.countDown() } - instrumentedHttpClient.get(new URI("${otherApp.address}bar")).then { latch.countDown() } - } - } - } - - app.test { httpClient -> - assert "hello" == httpClient.get("path-name").body.text - latch.await(1, TimeUnit.SECONDS) - - new PollingConditions().eventually { - spanExporter.finishedSpanItems.size() == 3 - def spanData = spanExporter.finishedSpanItems.find { spanData -> spanData.name == "GET /path-name" } - def spanClientData1 = spanExporter.finishedSpanItems.find { s -> s.name == "GET" && s.attributes.asMap()[HTTP_ROUTE] == "/foo" } - def spanClientData2 = spanExporter.finishedSpanItems.find { s -> s.name == "GET" && s.attributes.asMap()[HTTP_ROUTE] == "/bar" } - - spanData.traceId == spanClientData1.traceId - spanData.traceId == spanClientData2.traceId - - spanData.kind == SERVER - - spanClientData1.kind == CLIENT - def atts = spanClientData1.attributes.asMap() - atts[HTTP_ROUTE] == "/foo" - atts[HTTP_REQUEST_METHOD] == "GET" - atts[HTTP_RESPONSE_STATUS_CODE] == 200L - - spanClientData2.kind == CLIENT - def atts2 = spanClientData2.attributes.asMap() - atts2[HTTP_ROUTE] == "/bar" - atts2[HTTP_REQUEST_METHOD] == "GET" - atts2[HTTP_RESPONSE_STATUS_CODE] == 200L - - def attributes = spanData.attributes.asMap() - attributes[HTTP_ROUTE] == "/path-name" - attributes[UrlAttributes.URL_PATH] == "/path-name" - attributes[HTTP_REQUEST_METHOD] == "GET" - attributes[HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } - - def "handling exception errors in http client"() { - expect: - def otherApp = EmbeddedApp.of { spec -> - spec.handlers { - it.get("foo") { ctx -> - Promise.value("bar").defer(Duration.ofSeconds(1L)) - .then { ctx.render("bar") } - } - } - } - - def app = EmbeddedApp.of { spec -> - spec.registry( - Guice.registry { bindings -> - serverTelemetry.configureRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrument( - HttpClient.of { s -> s.readTimeout(Duration.ofMillis(10)) }) - ) - } - ) - - spec.handlers { chain -> - chain.get("path-name") { ctx -> - def instrumentedHttpClient = ctx.get(HttpClient) - instrumentedHttpClient.get(new URI("${otherApp.address}foo")) - .onError { ctx.render("error") } - .then { ctx.render("hello") } - } - } - } - - app.test { httpClient -> - assert "error" == httpClient.get("path-name").body.text - - new PollingConditions().eventually { - def spanData = spanExporter.finishedSpanItems.find { it.name == "GET /path-name" } - def spanClientData = spanExporter.finishedSpanItems.find { it.name == "GET" } - - spanData.traceId == spanClientData.traceId - - spanData.kind == SERVER - spanClientData.kind == CLIENT - def atts = spanClientData.attributes.asMap() - atts[HTTP_ROUTE] == "/foo" - atts[HTTP_REQUEST_METHOD] == "GET" - atts[HTTP_RESPONSE_STATUS_CODE] == null - spanClientData.status.statusCode == StatusCode.ERROR - spanClientData.events.first().name == "exception" - - def attributes = spanData.attributes.asMap() - attributes[HTTP_ROUTE] == "/path-name" - attributes[UrlAttributes.URL_PATH] == "/path-name" - attributes[HTTP_REQUEST_METHOD] == "GET" - attributes[HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } - - def "propagate http trace in ratpack services with compute thread"() { - expect: - def latch = new CountDownLatch(1) - - def otherApp = EmbeddedApp.of { spec -> - spec.handlers { - it.get("foo") { ctx -> ctx.render("bar") } - } - } - - def app = EmbeddedApp.of { spec -> - spec.registry( - Guice.registry { bindings -> - serverTelemetry.configureRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) - bindings.bindInstance(new BarService(latch, "${otherApp.address}foo", openTelemetry)) - }, - ) - spec.handlers { chain -> - chain.get("foo") { ctx -> ctx.render("bar") } - } - } - - app.address - latch.await() - new PollingConditions().eventually { - def spanData = spanExporter.finishedSpanItems.find { it.name == "a-span" } - def trace = spanExporter.finishedSpanItems.findAll { it.traceId == spanData.traceId } - - trace.size() == 3 - } - } - - def "propagate http trace in ratpack services with fork executions"() { - expect: - def latch = new CountDownLatch(1) - - def otherApp = EmbeddedApp.of { spec -> - spec.handlers { - it.get("foo") { ctx -> ctx.render("bar") } - } - } - - def app = EmbeddedApp.of { spec -> - spec.registry( - Guice.registry { bindings -> - serverTelemetry.configureRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) - bindings.bindInstance(new BarForkService(latch, "${otherApp.address}foo", openTelemetry)) - }, - ) - spec.handlers { chain -> - chain.get("foo") { ctx -> ctx.render("bar") } - } - } - - app.address - latch.await() - new PollingConditions().eventually { - def spanData = spanExporter.finishedSpanItems.find { it.name == "a-span" } - def trace = spanExporter.finishedSpanItems.findAll { it.traceId == spanData.traceId } - - trace.size() == 3 - } - } -} - -class BarService implements Service { - private final String url - private final CountDownLatch latch - private final OpenTelemetry openTelemetry - - BarService(CountDownLatch latch, String url, OpenTelemetry openTelemetry) { - this.latch = latch - this.url = url - this.openTelemetry = openTelemetry - } - - private Tracer tracer = openTelemetry.tracerProvider.tracerBuilder("testing").build() - - void onStart(StartEvent event) { - def parentContext = Context.current() - def span = tracer.spanBuilder("a-span") - .setParent(parentContext) - .startSpan() - - Context otelContext = parentContext.with(span) - otelContext.makeCurrent().withCloseable { - Execution.current().add(Context, otelContext) - def httpClient = event.registry.get(HttpClient) - httpClient.get(new URI(url)) - .flatMap { httpClient.get(new URI(url)) } - .then { - span.end() - latch.countDown() - } - } - } -} - -class BarForkService implements Service { - private final String url - private final CountDownLatch latch - private final OpenTelemetry openTelemetry - - BarForkService(CountDownLatch latch, String url, OpenTelemetry openTelemetry) { - this.latch = latch - this.url = url - this.openTelemetry = openTelemetry - } - - private Tracer tracer = openTelemetry.tracerProvider.tracerBuilder("testing").build() - - void onStart(StartEvent event) { - Execution.fork().start { - def parentContext = Context.current() - def span = tracer.spanBuilder("a-span") - .setParent(parentContext) - .startSpan() - - Context otelContext = parentContext.with(span) - otelContext.makeCurrent().withCloseable { - Execution.current().add(Context, otelContext) - def httpClient = event.registry.get(HttpClient) - httpClient.get(new URI(url)) - .flatMap { httpClient.get(new URI(url)) } - .then { - span.end() - latch.countDown() - } - } - } - } -} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy deleted file mode 100644 index d2ca21755a9c..000000000000 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.ratpack.v1_7.server - -import com.google.inject.AbstractModule -import com.google.inject.Provides -import groovy.transform.CompileStatic -import io.opentelemetry.api.OpenTelemetry -import io.opentelemetry.api.trace.SpanKind -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetry -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackFunctionalTest -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry -import io.opentelemetry.sdk.OpenTelemetrySdk -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter -import io.opentelemetry.sdk.trace.SdkTracerProvider -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor -import io.opentelemetry.sdk.trace.export.SpanExporter -import ratpack.exec.ExecInitializer -import ratpack.exec.ExecInterceptor -import ratpack.guice.Guice -import ratpack.handling.Handler -import ratpack.http.client.HttpClient -import ratpack.server.RatpackServer -import spock.lang.Specification -import spock.util.concurrent.PollingConditions - -import javax.inject.Singleton - -import static io.opentelemetry.semconv.HttpAttributes.* -import static io.opentelemetry.semconv.UrlAttributes.URL_PATH - -class RatpackServerApplicationTest extends Specification { - - def app = new RatpackFunctionalTest(RatpackApp) - - def "add span on handlers"() { - expect: - app.test { httpClient -> - assert "hi-foo" == httpClient.get("foo").body.text - - new PollingConditions().eventually { - def spanData = app.spanExporter.finishedSpanItems.find { it.name == "GET /foo" } - def attributes = spanData.attributes.asMap() - - spanData.kind == SpanKind.SERVER - attributes[HTTP_ROUTE] == "/foo" - attributes[URL_PATH] == "/foo" - attributes[HTTP_REQUEST_METHOD] == "GET" - attributes[HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } - - def "propagate trace to http calls"() { - expect: - app.test { httpClient -> - assert "hi-bar" == httpClient.get("bar").body.text - - new PollingConditions().eventually { - def spanData = app.spanExporter.finishedSpanItems.find { it.name == "GET /bar" } - def spanDataClient = app.spanExporter.finishedSpanItems.find { it.name == "GET" } - def attributes = spanData.attributes.asMap() - - spanData.traceId == spanDataClient.traceId - - spanData.kind == SpanKind.SERVER - attributes[HTTP_ROUTE] == "/bar" - attributes[URL_PATH] == "/bar" - attributes[HTTP_REQUEST_METHOD] == "GET" - attributes[HTTP_RESPONSE_STATUS_CODE] == 200L - - spanDataClient.kind == SpanKind.CLIENT - def attributesClient = spanDataClient.attributes.asMap() - attributesClient[HTTP_ROUTE] == "/other" - attributesClient[HTTP_REQUEST_METHOD] == "GET" - attributesClient[HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } - - def "ignore handlers before OpenTelemetryServerHandler"() { - expect: - app.test { httpClient -> - assert "ignored" == httpClient.get("ignore").body.text - - new PollingConditions(initialDelay: 0.1, timeout: 0.3).eventually { - !app.spanExporter.finishedSpanItems.any { it.name == "GET /ignore" } - } - } - } -} - - -@CompileStatic -class OpenTelemetryModule extends AbstractModule { - @Override - protected void configure() { - bind(SpanExporter).toInstance(InMemorySpanExporter.create()) - } - - @Singleton - @Provides - RatpackClientTelemetry ratpackClientTelemetry(OpenTelemetry openTelemetry) { - return RatpackClientTelemetry.create(openTelemetry) - } - - @Singleton - @Provides - RatpackServerTelemetry ratpackServerTelemetry(OpenTelemetry openTelemetry) { - return RatpackServerTelemetry.create(openTelemetry) - } - - @Singleton - @Provides - Handler ratpackServerHandler(RatpackServerTelemetry ratpackTracing) { - return ratpackTracing.getHandler() - } - - @Singleton - @Provides - ExecInterceptor ratpackExecInterceptor(RatpackServerTelemetry ratpackTracing) { - return ratpackTracing.getExecInterceptor() - } - - @Provides - @Singleton - OpenTelemetry providesOpenTelemetry(SpanExporter spanExporter) { - def tracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build() - return OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build() - } - - @Singleton - @Provides - HttpClient instrumentedHttpClient(RatpackClientTelemetry ratpackTracing) { - return ratpackTracing.instrument(HttpClient.of {}) - } - - @Singleton - @Provides - ExecInitializer ratpackExecInitializer(RatpackServerTelemetry ratpackTracing) { - return ratpackTracing.getExecInitializer() - } -} - -@CompileStatic -class RatpackApp { - - static void main(String... args) { - RatpackServer.start { server -> - server - .registry(Guice.registry { b -> b.module(OpenTelemetryModule) }) - .handlers { chain -> - chain - .get("ignore") { ctx -> ctx.render("ignored") } - .all(Handler) - .get("foo") { ctx -> ctx.render("hi-foo") } - .get("bar") { ctx -> - ctx.get(HttpClient).get(ctx.get(URI)) - .then { ctx.render("hi-bar") } - } - } - } - } -} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy deleted file mode 100644 index a997419d8730..000000000000 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.ratpack.v1_7.server - -import io.opentelemetry.api.trace.SpanKind -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator -import io.opentelemetry.context.propagation.ContextPropagators -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry -import io.opentelemetry.sdk.OpenTelemetrySdk -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter -import io.opentelemetry.sdk.trace.SdkTracerProvider -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor -import io.opentelemetry.semconv.HttpAttributes -import io.opentelemetry.semconv.UrlAttributes -import ratpack.exec.Blocking -import ratpack.registry.Registry -import ratpack.test.embed.EmbeddedApp -import spock.lang.Specification -import spock.util.concurrent.PollingConditions - -class RatpackServerTest2 extends Specification { - - def spanExporter = InMemorySpanExporter.create() - def tracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build() - - def openTelemetry = OpenTelemetrySdk.builder() - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setTracerProvider(tracerProvider).build() - - def telemetry = RatpackServerTelemetry.create(openTelemetry) - - def cleanup() { - spanExporter.reset() - } - - def "add span on handlers"() { - given: - def app = EmbeddedApp.of { spec -> - spec.registry { Registry.of { telemetry.configureRegistry(it) } } - spec.handlers { chain -> - chain.get("foo") { ctx -> ctx.render("hi-foo") } - } - } - - expect: - app.test { httpClient -> - assert "hi-foo" == httpClient.get("foo").body.text - - new PollingConditions().eventually { - def spanData = spanExporter.finishedSpanItems.find { it.name == "GET /foo" } - def attributes = spanData.attributes.asMap() - - spanData.kind == SpanKind.SERVER - attributes[HttpAttributes.HTTP_ROUTE] == "/foo" - attributes[UrlAttributes.URL_PATH] == "/foo" - attributes[HttpAttributes.HTTP_REQUEST_METHOD] == "GET" - attributes[HttpAttributes.HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } - - def "propagate trace with instrumented async operations"() { - expect: - def app = EmbeddedApp.of { spec -> - spec.registry { Registry.of { telemetry.configureRegistry(it) } } - spec.handlers { chain -> - chain.get("foo") { ctx -> - ctx.render("hi-foo") - Blocking.op { - def span = openTelemetry.getTracer("any-tracer").spanBuilder("a-span").startSpan() - span.makeCurrent().withCloseable { - span.addEvent("an-event") - span.end() - } - }.then() - } - } - } - - app.test { httpClient -> - assert "hi-foo" == httpClient.get("foo").body.text - - new PollingConditions().eventually { - def spanData = spanExporter.finishedSpanItems.find { it.name == "GET /foo" } - def spanDataChild = spanExporter.finishedSpanItems.find { it.name == "a-span" } - - spanData.kind == SpanKind.SERVER - spanData.traceId == spanDataChild.traceId - spanDataChild.parentSpanId == spanData.spanId - spanDataChild.events.any { it.name == "an-event" } - - def attributes = spanData.attributes.asMap() - attributes[HttpAttributes.HTTP_ROUTE] == "/foo" - attributes[UrlAttributes.URL_PATH] == "/foo" - attributes[HttpAttributes.HTTP_REQUEST_METHOD] == "GET" - attributes[HttpAttributes.HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } - - def "propagate trace with instrumented async concurrent operations"() { - expect: - def app = EmbeddedApp.of { spec -> - spec.registry { Registry.of { telemetry.configureRegistry(it) } } - spec.handlers { chain -> - chain.get("bar") { ctx -> - ctx.render("hi-bar") - Blocking.op { - def span = openTelemetry.getTracer("any-tracer").spanBuilder("another-span").startSpan() - span.makeCurrent().withCloseable { - span.addEvent("an-event") - span.end() - } - }.then() - } - chain.get("foo") { ctx -> - ctx.render("hi-foo") - Blocking.op { - def span = openTelemetry.getTracer("any-tracer").spanBuilder("a-span").startSpan() - span.makeCurrent().withCloseable { - span.addEvent("an-event") - span.end() - } - }.then() - } - } - } - - app.test { httpClient -> - assert "hi-foo" == httpClient.get("foo").body.text - assert "hi-bar" == httpClient.get("bar").body.text - - new PollingConditions().eventually { - def spanData = spanExporter.finishedSpanItems.find { it.name == "GET /foo" } - def spanDataChild = spanExporter.finishedSpanItems.find { it.name == "a-span" } - - def spanData2 = spanExporter.finishedSpanItems.find { it.name == "GET /bar" } - def spanDataChild2 = spanExporter.finishedSpanItems.find { it.name == "another-span" } - - spanData.kind == SpanKind.SERVER - spanData.traceId == spanDataChild.traceId - spanDataChild.parentSpanId == spanData.spanId - spanDataChild.events.any { it.name == "an-event" } - - spanData2.kind == SpanKind.SERVER - spanData2.traceId == spanDataChild2.traceId - spanDataChild2.parentSpanId == spanData2.spanId - spanDataChild2.events.any { it.name == "an-event" } - - def attributes = spanData.attributes.asMap() - attributes[HttpAttributes.HTTP_ROUTE] == "/foo" - attributes[UrlAttributes.URL_PATH] == "/foo" - attributes[HttpAttributes.HTTP_REQUEST_METHOD] == "GET" - attributes[HttpAttributes.HTTP_RESPONSE_STATUS_CODE] == 200L - } - } - } -} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java new file mode 100644 index 000000000000..5b1888164a8f --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import org.junit.jupiter.api.AfterEach; + +public abstract class AbstractRatpackTest { + protected final InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + private final SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + + protected OpenTelemetry openTelemetry = + OpenTelemetrySdk.builder() + .setPropagators(ContextPropagators.create(W3CBaggagePropagator.getInstance())) + .setTracerProvider(tracerProvider) + .build(); + + protected RatpackClientTelemetry telemetry = RatpackClientTelemetry.create(openTelemetry); + protected RatpackServerTelemetry serverTelemetry = RatpackServerTelemetry.create(openTelemetry); + + @AfterEach + void cleanup() { + spanExporter.reset(); + } + + protected SpanData findSpanData(String spanName, SpanKind spanKind) { + return spanExporter.getFinishedSpanItems().stream() + .filter(span -> spanName.equals(span.getName()) && span.getKind().equals(spanKind)) + .findFirst() + .orElseThrow(() -> new AssertionError("Span not found")); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java new file mode 100644 index 000000000000..7dbb2d808a4d --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java @@ -0,0 +1,56 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.client; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import ratpack.exec.Execution; +import ratpack.exec.Operation; +import ratpack.http.client.HttpClient; +import ratpack.service.Service; +import ratpack.service.StartEvent; + +public class BarForkService implements Service { + private final String url; + private final CountDownLatch latch; + private final Tracer tracer; + + public BarForkService(CountDownLatch latch, String url, OpenTelemetry openTelemetry) { + this.latch = latch; + this.url = url; + this.tracer = openTelemetry.getTracerProvider().tracerBuilder("testing").build(); + } + + @Override + public void onStart(StartEvent event) { + Execution.fork() + .start( + Operation.of( + () -> { + Context parentContext = Context.current(); + Span span = tracer.spanBuilder("a-span").setParent(parentContext).startSpan(); + + Context otelContext = parentContext.with(span); + try (Scope scope = otelContext.makeCurrent()) { + Execution.current().add(Context.class, otelContext); + HttpClient httpClient = event.getRegistry().get(HttpClient.class); + httpClient + .get(new URI(url)) + .flatMap(response -> httpClient.get(new URI(url))) + .then( + response -> { + span.end(); + latch.countDown(); + }); + } + })); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java new file mode 100644 index 000000000000..2a3e374c6ea3 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.client; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.CountDownLatch; +import ratpack.exec.Execution; +import ratpack.http.client.HttpClient; +import ratpack.service.Service; +import ratpack.service.StartEvent; + +public class BarService implements Service { + private final String url; + private final CountDownLatch latch; + private final Tracer tracer; + + public BarService(CountDownLatch latch, String url, OpenTelemetry openTelemetry) { + this.latch = latch; + this.url = url; + this.tracer = openTelemetry.getTracerProvider().tracerBuilder("testing").build(); + } + + @Override + public void onStart(StartEvent event) { + Context parentContext = Context.current(); + Span span = tracer.spanBuilder("a-span").setParent(parentContext).startSpan(); + + Context otelContext = parentContext.with(span); + try (Scope scope = otelContext.makeCurrent()) { + Execution.current().add(Context.class, otelContext); + HttpClient httpClient = event.getRegistry().get(HttpClient.class); + httpClient + .get(new URI(url)) + .flatMap(response -> httpClient.get(new URI(url))) + .then( + response -> { + span.end(); + latch.countDown(); + }); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java new file mode 100644 index 000000000000..14c666365ea3 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java @@ -0,0 +1,357 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.client; + +import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE; +import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.instrumentation.ratpack.v1_7.AbstractRatpackTest; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.net.URI; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; +import ratpack.exec.Promise; +import ratpack.func.Action; +import ratpack.guice.Guice; +import ratpack.http.client.HttpClient; +import ratpack.test.embed.EmbeddedApp; + +class InstrumentedHttpClientTest extends AbstractRatpackTest { + + @Test + void testPropagateTraceWithHttpCalls() throws Exception { + EmbeddedApp otherApp = + EmbeddedApp.of( + spec -> { + spec.registry( + Guice.registry(bindings -> serverTelemetry.configureRegistry(bindings))); + spec.handlers(chain -> chain.get("bar", ctx -> ctx.render("foo"))); + }); + + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + Guice.registry( + bindings -> { + serverTelemetry.configureRegistry(bindings); + bindings.bindInstance( + HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); + })); + + spec.handlers( + chain -> + chain.get( + "foo", + ctx -> { + HttpClient instrumentedHttpClient = ctx.get(HttpClient.class); + instrumentedHttpClient + .get(new URI(otherApp.getAddress().toString() + "bar")) + .then(response -> ctx.render("bar")); + })); + }); + + app.test( + httpClient -> { + assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("bar"); + + await() + .untilAsserted( + () -> { + SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); + SpanData spanClientData = findSpanData("GET", SpanKind.CLIENT); + SpanData spanDataApi = findSpanData("GET /bar", SpanKind.SERVER); + + assertThat(spanData.getTraceId()).isEqualTo(spanClientData.getTraceId()); + + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(spanClientData.getKind()).isEqualTo(SpanKind.CLIENT); + + Map, Object> clientAttributes = + spanClientData.getAttributes().asMap(); + assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/bar"); + assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + + Map, Object> attributes = spanData.getAttributes().asMap(); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + + Map, Object> apiAttributes = + spanDataApi.getAttributes().asMap(); + assertThat(apiAttributes.get(HTTP_ROUTE)).isEqualTo("/bar"); + assertThat(apiAttributes.get(URL_PATH)).isEqualTo("/bar"); + assertThat(apiAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(apiAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); + } + + @Test + void testAddSpansForMultipleConcurrentClientCalls() throws Exception { + CountDownLatch latch = new CountDownLatch(2); + + EmbeddedApp otherApp = + EmbeddedApp.of( + spec -> + spec.handlers( + chain -> { + chain.get("foo", ctx -> ctx.render("bar")); + chain.get("bar", ctx -> ctx.render("foo")); + })); + + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + Guice.registry( + bindings -> { + serverTelemetry.configureRegistry(bindings); + bindings.bindInstance( + HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); + })); + spec.handlers( + chain -> + chain.get( + "path-name", + ctx -> { + ctx.render("hello"); + HttpClient instrumentedHttpClient = ctx.get(HttpClient.class); + instrumentedHttpClient + .get(new URI(otherApp.getAddress().toString() + "foo")) + .then(response -> latch.countDown()); + instrumentedHttpClient + .get(new URI(otherApp.getAddress().toString() + "bar")) + .then(response -> latch.countDown()); + })); + }); + + app.test( + httpClient -> { + assertThat(httpClient.get("path-name").getBody().getText()).isEqualTo("hello"); + latch.await(1, TimeUnit.SECONDS); + + await() + .untilAsserted( + () -> { + assertThat(spanExporter.getFinishedSpanItems().size()).isEqualTo(3); + + SpanData spanData = findSpanData("GET /path-name", SpanKind.SERVER); + + SpanData spanClientData1 = + spanExporter.getFinishedSpanItems().stream() + .filter( + span -> + "GET".equals(span.getName()) + && span.getAttributes() + .asMap() + .get(HTTP_ROUTE) + .equals("/foo")) + .findFirst() + .orElseThrow(() -> new AssertionError("Span not found")); + + SpanData spanClientData2 = + spanExporter.getFinishedSpanItems().stream() + .filter( + span -> + "GET".equals(span.getName()) + && span.getAttributes() + .asMap() + .get(HTTP_ROUTE) + .equals("/bar")) + .findFirst() + .orElseThrow(() -> new AssertionError("Span not found")); + + assertThat(spanData.getTraceId()).isEqualTo(spanClientData1.getTraceId()); + assertThat(spanData.getTraceId()).isEqualTo(spanClientData2.getTraceId()); + + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + + assertThat(spanClientData1.getKind()).isEqualTo(SpanKind.CLIENT); + Map, Object> clientAttributes = + spanClientData1.getAttributes().asMap(); + assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/foo"); + assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + + assertThat(spanClientData2.getKind()).isEqualTo(SpanKind.CLIENT); + Map, Object> client2Attributes = + spanClientData2.getAttributes().asMap(); + assertThat(client2Attributes.get(HTTP_ROUTE)).isEqualTo("/bar"); + assertThat(client2Attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(client2Attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + + Map, Object> attributes = spanData.getAttributes().asMap(); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/path-name"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/path-name"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); + } + + @Test + void testHandlingExceptionErrorsInHttpClient() throws Exception { + + EmbeddedApp otherApp = + EmbeddedApp.of( + spec -> + spec.handlers( + chain -> + chain.get( + "foo", + ctx -> + Promise.value("bar") + .defer(Duration.ofSeconds(1L)) + .then(value -> ctx.render("bar"))))); + + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + Guice.registry( + bindings -> { + serverTelemetry.configureRegistry(bindings); + bindings.bindInstance( + HttpClient.class, + telemetry.instrument( + HttpClient.of(s -> s.readTimeout(Duration.ofMillis(10))))); + })); + + spec.handlers( + chain -> + chain.get( + "path-name", + ctx -> { + HttpClient instrumentedHttpClient = ctx.get(HttpClient.class); + instrumentedHttpClient + .get(new URI(otherApp.getAddress().toString() + "foo")) + .onError(throwable -> ctx.render("error")) + .then(response -> ctx.render("hello")); + })); + }); + + app.test( + httpClient -> { + assertThat(httpClient.get("path-name").getBody().getText()).isEqualTo("error"); + + await() + .untilAsserted( + () -> { + SpanData spanData = findSpanData("GET /path-name", SpanKind.SERVER); + SpanData spanClientData = findSpanData("GET", SpanKind.CLIENT); + + assertThat(spanData.getTraceId()).isEqualTo(spanClientData.getTraceId()); + + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(spanClientData.getKind()).isEqualTo(SpanKind.CLIENT); + Map, Object> clientAttributes = + spanClientData.getAttributes().asMap(); + assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/foo"); + assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isNull(); + assertThat(spanClientData.getStatus().getStatusCode()) + .isEqualTo(StatusCode.ERROR); + assertThat(spanClientData.getEvents().stream().findFirst().get().getName()) + .isEqualTo("exception"); + + Map, Object> attributes = spanData.getAttributes().asMap(); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/path-name"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/path-name"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); + } + + @Test + void testPropagateHttpTraceInRatpackServicesWithComputeThread() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + + EmbeddedApp otherApp = + EmbeddedApp.of(spec -> spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar")))); + + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + Guice.registry( + bindings -> { + serverTelemetry.configureRegistry(bindings); + bindings.bindInstance( + HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); + bindings.bindInstance( + new BarService( + latch, otherApp.getAddress().toString() + "foo", openTelemetry)); + })); + + spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar"))); + }); + + app.getAddress(); + latch.await(); + await() + .untilAsserted( + () -> { + SpanData spanData = findSpanData("a-span", SpanKind.INTERNAL); + assertThat( + spanExporter.getFinishedSpanItems().stream() + .filter(span -> span.getTraceId().equals(spanData.getTraceId())) + .count()) + .isEqualTo(3); + }); + } + + @Test + void propagateHttpTraceInRatpackServicesWithForkExecutions() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + + EmbeddedApp otherApp = + EmbeddedApp.of(spec -> spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar")))); + + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + Guice.registry( + bindings -> { + serverTelemetry.configureRegistry(bindings); + bindings.bindInstance( + HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); + bindings.bindInstance( + new BarForkService( + latch, otherApp.getAddress().toString() + "foo", openTelemetry)); + })); + + spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar"))); + }); + + app.getAddress(); + latch.await(); + await() + .untilAsserted( + () -> { + SpanData spanData = findSpanData("a-span", SpanKind.INTERNAL); + assertThat( + spanExporter.getFinishedSpanItems().stream() + .filter(span -> span.getTraceId().equals(spanData.getTraceId())) + .count()) + .isEqualTo(3); + }); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java new file mode 100644 index 000000000000..0102653459ec --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.server; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetry; +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import javax.inject.Singleton; +import ratpack.exec.ExecInitializer; +import ratpack.exec.ExecInterceptor; +import ratpack.func.Action; +import ratpack.handling.Handler; +import ratpack.http.client.HttpClient; + +public class OpenTelemetryModule extends AbstractModule { + @Override + protected void configure() { + bind(SpanExporter.class).toInstance(InMemorySpanExporter.create()); + } + + @Singleton + @Provides + RatpackClientTelemetry ratpackClientTelemetry(OpenTelemetry openTelemetry) { + return RatpackClientTelemetry.create(openTelemetry); + } + + @Singleton + @Provides + RatpackServerTelemetry ratpackServerTelemetry(OpenTelemetry openTelemetry) { + return RatpackServerTelemetry.create(openTelemetry); + } + + @Singleton + @Provides + Handler ratpackServerHandler(RatpackServerTelemetry ratpackTracing) { + return ratpackTracing.getHandler(); + } + + @Singleton + @Provides + ExecInterceptor ratpackExecInterceptor(RatpackServerTelemetry ratpackTracing) { + return ratpackTracing.getExecInterceptor(); + } + + @Provides + @Singleton + OpenTelemetry providesOpenTelemetry(SpanExporter spanExporter) { + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + return OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); + } + + @Singleton + @Provides + HttpClient instrumentedHttpClient(RatpackClientTelemetry ratpackTracing) throws Exception { + return ratpackTracing.instrument(HttpClient.of(Action.noop())); + } + + @Singleton + @Provides + ExecInitializer ratpackExecInitializer(RatpackServerTelemetry ratpackTracing) { + return ratpackTracing.getExecInitializer(); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java new file mode 100644 index 000000000000..ac73972fd063 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.server; + +import java.net.URI; +import ratpack.guice.Guice; +import ratpack.handling.Handler; +import ratpack.http.client.HttpClient; +import ratpack.server.RatpackServer; + +public class RatpackApp { + public static void main(String... args) throws Exception { + RatpackServer.start( + server -> + server + .registry(Guice.registry(b -> b.module(OpenTelemetryModule.class))) + .handlers( + chain -> + chain + .get("ignore", ctx -> ctx.render("ignored")) + .all(Handler.class) + .get("foo", ctx -> ctx.render("hi-foo")) + .get( + "bar", + ctx -> + ctx.get(HttpClient.class) + .get(ctx.get(URI.class)) + .then(response -> ctx.render("hi-bar"))))); + } + + private RatpackApp() {} +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java new file mode 100644 index 000000000000..246511c498d4 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.server; + +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.net.URI; +import ratpack.guice.BindingsImposition; +import ratpack.impose.ForceDevelopmentImposition; +import ratpack.impose.ImpositionsSpec; +import ratpack.impose.UserRegistryImposition; +import ratpack.registry.Registry; +import ratpack.test.MainClassApplicationUnderTest; +import ratpack.test.embed.EmbeddedApp; + +public class RatpackFunctionalTest extends MainClassApplicationUnderTest { + + private Registry registry; + protected InMemorySpanExporter spanExporter; + private final EmbeddedApp app; + + public RatpackFunctionalTest(Class mainClass) throws Exception { + super(mainClass); + this.app = + EmbeddedApp.of( + server -> server.handlers(chain -> chain.get("other", ctx -> ctx.render("hi-other")))); + getAddress(); + } + + @Override + protected void addImpositions(ImpositionsSpec impositions) { + impositions.add(ForceDevelopmentImposition.of(false)); + impositions.add( + UserRegistryImposition.of( + r -> { + registry = r; + spanExporter = (InMemorySpanExporter) registry.get(SpanExporter.class); + return registry; + })); + impositions.add( + BindingsImposition.of( + bindings -> bindings.bindInstance(URI.class, app.getAddress().resolve("other")))); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java new file mode 100644 index 000000000000..54106f7361e7 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java @@ -0,0 +1,109 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.server; + +import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE; +import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class RatpackServerApplicationTest { + + private final RatpackFunctionalTest app = new RatpackFunctionalTest(RatpackApp.class); + + @Test + void testAddSpanOnHandlers() throws Exception { + app.test( + httpClient -> { + assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); + + await() + .untilAsserted( + () -> { + SpanData spanData = + app.spanExporter.getFinishedSpanItems().stream() + .filter(span -> "GET /foo".equals(span.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Span not found")); + + Map, Object> attributes = spanData.getAttributes().asMap(); + + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); + } + + @Test + void testPropagateTraceToHttpCalls() throws Exception { + app.test( + httpClient -> { + assertThat(httpClient.get("bar").getBody().getText()).isEqualTo("hi-bar"); + + await() + .untilAsserted( + () -> { + SpanData spanData = + app.spanExporter.getFinishedSpanItems().stream() + .filter(span -> "GET /bar".equals(span.getName())) + .findFirst() + .orElseThrow(() -> new AssertionError("Span not found")); + + SpanData spanDataClient = + app.spanExporter.getFinishedSpanItems().stream() + .filter(span -> span.getName().equals("GET")) + .findFirst() + .orElseThrow(() -> new AssertionError("Span not found")); + + assertThat(spanData.getTraceId()).isEqualTo(spanDataClient.getTraceId()); + + Map, Object> attributes = spanData.getAttributes().asMap(); + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/bar"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/bar"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + + Map, Object> clientAttributes = + spanDataClient.getAttributes().asMap(); + + assertThat(spanDataClient.getKind()).isEqualTo(SpanKind.CLIENT); + assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/other"); + assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); + } + + @Test + void testIgnoreHandlersBeforeOpenTelemetryServerHandler() throws Exception { + app.test( + httpClient -> { + assertThat(httpClient.get("ignore").getBody().getText()).isEqualTo("ignored"); + + await() + .untilAsserted( + () -> + assertThat( + app.spanExporter.getFinishedSpanItems().stream() + .noneMatch(span -> "GET /ignore".equals(span.getName()))) + .isTrue()); + }); + } + + RatpackServerApplicationTest() throws Exception {} +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java index 2e3fdad3d4ca..faedec80ee43 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java @@ -1,63 +1,205 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.instrumentation.ratpack.v1_7.server; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE; +import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; -import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.ratpack.v1_7.AbstractRatpackTest; import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; -import org.junit.jupiter.api.AfterAll; +import java.util.Map; import org.junit.jupiter.api.Test; +import ratpack.exec.Blocking; import ratpack.registry.Registry; import ratpack.test.embed.EmbeddedApp; -import spock.util.concurrent.PollingConditions; -import java.util.Map; -import java.util.stream.Collectors; +class RatpackServerTest extends AbstractRatpackTest { -import static org.assertj.core.api.Assertions.assertThat; + @Test + void testAddSpanOnHandlers() throws Exception { + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + registry -> Registry.of(regSpec -> serverTelemetry.configureRegistry(regSpec))); + spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("hi-foo"))); + }); -class RatpackServerTest { + app.test( + httpClient -> { + assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - private static InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); - private SdkTracerProvider tracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build(); + await() + .untilAsserted( + () -> { + SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); + Map, Object> attributes = spanData.getAttributes().asMap(); - OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() - .setPropagators(ContextPropagators.create(W3CBaggagePropagator.getInstance())) - .setTracerProvider(tracerProvider).build(); + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); + } + + @Test + void testPropagateTraceWithInstrumentedAsyncOperations() throws Exception { + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + registry -> Registry.of(regSpec -> serverTelemetry.configureRegistry(regSpec))); + spec.handlers( + chain -> + chain.get( + "foo", + ctx -> { + ctx.render("hi-foo"); + Blocking.op( + () -> { + Span span = + openTelemetry + .getTracer("any-tracer") + .spanBuilder("a-span") + .startSpan(); + try (Scope scope = span.makeCurrent()) { + span.addEvent("an-event"); + } finally { + span.end(); + } + }) + .then(); + })); + }); + + app.test( + httpClient -> { + assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - RatpackServerTelemetry telemetry = RatpackServerTelemetry.create(openTelemetry); + await() + .untilAsserted( + () -> { + SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); + SpanData spanDataChild = findSpanData("a-span", SpanKind.INTERNAL); - @AfterAll - static void cleanup() { - spanExporter.reset(); + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(spanData.getTraceId()).isEqualTo(spanDataChild.getTraceId()); + assertThat(spanDataChild.getParentSpanId()).isEqualTo(spanData.getSpanId()); + assertThat( + spanDataChild.getEvents().stream() + .filter(event -> "an-event".equals(event.getName())) + .count()) + .isEqualTo(1); + + Map, Object> attributes = spanData.getAttributes().asMap(); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); } @Test - void testAddSpanOnHandlers() throws Exception { - EmbeddedApp app = EmbeddedApp.of( - spec -> { - spec.registry(registry -> Registry.of(regSpec -> telemetry.configureRegistry(regSpec))); - spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("hi-foo"))); - } - ); + void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Exception { + EmbeddedApp app = + EmbeddedApp.of( + spec -> { + spec.registry( + registry -> Registry.of(regSpec -> serverTelemetry.configureRegistry(regSpec))); + spec.handlers( + chain -> { + chain.get( + "bar", + ctx -> { + ctx.render("hi-bar"); + Blocking.op( + () -> { + Span span = + openTelemetry + .getTracer("any-tracer") + .spanBuilder("another-span") + .startSpan(); + try (Scope scope = span.makeCurrent()) { + span.addEvent("an-event"); + } finally { + span.end(); + } + }) + .then(); + }); + chain.get( + "foo", + ctx -> { + ctx.render("hi-foo"); + Blocking.op( + () -> { + Span span = + openTelemetry + .getTracer("any-tracer") + .spanBuilder("a-span") + .startSpan(); + try (Scope scope = span.makeCurrent()) { + span.addEvent("an-event"); + } finally { + span.end(); + } + }) + .then(); + }); + }); + }); - app.test( httpClient -> { - assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - new PollingConditions().eventually(() -> { - Map spans = spanExporter.getFinishedSpanItems().stream() - .collect(Collectors.toMap(SpanData::getName, span -> span)); - assertThat(spans).containsKey("GET /foo"); + app.test( + httpClient -> { + assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); + assertThat(httpClient.get("bar").getBody().getText()).isEqualTo("hi-bar"); + await() + .untilAsserted( + () -> { + SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); + SpanData spanDataChild = findSpanData("a-span", SpanKind.INTERNAL); + SpanData spanData2 = findSpanData("GET /bar", SpanKind.SERVER); + SpanData spanDataChild2 = findSpanData("another-span", SpanKind.INTERNAL); - }); + assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(spanData.getTraceId()).isEqualTo(spanDataChild.getTraceId()); + assertThat(spanDataChild.getParentSpanId()).isEqualTo(spanData.getSpanId()); + assertThat( + spanDataChild.getEvents().stream() + .filter(event -> "an-event".equals(event.getName())) + .count()) + .isEqualTo(1); - } + assertThat(spanData2.getKind()).isEqualTo(SpanKind.SERVER); + assertThat(spanData2.getTraceId()).isEqualTo(spanDataChild2.getTraceId()); + assertThat(spanDataChild2.getParentSpanId()).isEqualTo(spanData2.getSpanId()); + assertThat( + spanDataChild2.getEvents().stream() + .filter(event -> "an-event".equals(event.getName())) + .count()) + .isEqualTo(1); + Map, Object> attributes = spanData.getAttributes().asMap(); + assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); + assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); + assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); + assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); + }); + }); + } } From 7c8843817edd227e23019e6a764017867836f16f Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Sat, 4 Jan 2025 07:47:01 -0500 Subject: [PATCH 4/9] convert to standard test methods --- .../ratpack/v1_7/AbstractRatpackTest.java | 46 -- .../ratpack/v1_7/client/BarForkService.java | 43 +- .../ratpack/v1_7/client/BarService.java | 57 ++- .../client/InstrumentedHttpClientTest.java | 447 ++++++++++-------- .../v1_7/server/OpenTelemetryModule.java | 27 +- .../ratpack/v1_7/server/RatpackApp.java | 5 +- .../v1_7/server/RatpackFunctionalTest.java | 24 +- .../server/RatpackServerApplicationTest.java | 143 +++--- .../v1_7/server/RatpackServerTest.java | 244 +++++----- 9 files changed, 493 insertions(+), 543 deletions(-) delete mode 100644 instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java deleted file mode 100644 index 5b1888164a8f..000000000000 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/AbstractRatpackTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.ratpack.v1_7; - -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; -import org.junit.jupiter.api.AfterEach; - -public abstract class AbstractRatpackTest { - protected final InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); - private final SdkTracerProvider tracerProvider = - SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build(); - - protected OpenTelemetry openTelemetry = - OpenTelemetrySdk.builder() - .setPropagators(ContextPropagators.create(W3CBaggagePropagator.getInstance())) - .setTracerProvider(tracerProvider) - .build(); - - protected RatpackClientTelemetry telemetry = RatpackClientTelemetry.create(openTelemetry); - protected RatpackServerTelemetry serverTelemetry = RatpackServerTelemetry.create(openTelemetry); - - @AfterEach - void cleanup() { - spanExporter.reset(); - } - - protected SpanData findSpanData(String spanName, SpanKind spanKind) { - return spanExporter.getFinishedSpanItems().stream() - .filter(span -> spanName.equals(span.getName()) && span.getKind().equals(spanKind)) - .findFirst() - .orElseThrow(() -> new AssertionError("Span not found")); - } -} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java index 7dbb2d808a4d..666c23ee65f5 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarForkService.java @@ -5,52 +5,19 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.client; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import java.net.URI; -import java.util.concurrent.CountDownLatch; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import ratpack.exec.Execution; import ratpack.exec.Operation; -import ratpack.http.client.HttpClient; -import ratpack.service.Service; import ratpack.service.StartEvent; -public class BarForkService implements Service { - private final String url; - private final CountDownLatch latch; - private final Tracer tracer; +public class BarForkService extends BarService { - public BarForkService(CountDownLatch latch, String url, OpenTelemetry openTelemetry) { - this.latch = latch; - this.url = url; - this.tracer = openTelemetry.getTracerProvider().tracerBuilder("testing").build(); + public BarForkService(String url, InstrumentationExtension testing) { + super(url, testing); } @Override public void onStart(StartEvent event) { - Execution.fork() - .start( - Operation.of( - () -> { - Context parentContext = Context.current(); - Span span = tracer.spanBuilder("a-span").setParent(parentContext).startSpan(); - - Context otelContext = parentContext.with(span); - try (Scope scope = otelContext.makeCurrent()) { - Execution.current().add(Context.class, otelContext); - HttpClient httpClient = event.getRegistry().get(HttpClient.class); - httpClient - .get(new URI(url)) - .flatMap(response -> httpClient.get(new URI(url))) - .then( - response -> { - span.end(); - latch.countDown(); - }); - } - })); + Execution.fork().start(Operation.of(() -> generateSpan(event))); } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java index 2a3e374c6ea3..faab66db485b 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java @@ -5,14 +5,12 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.client; -import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import java.net.URI; import java.net.URISyntaxException; -import java.util.concurrent.CountDownLatch; import ratpack.exec.Execution; import ratpack.http.client.HttpClient; import ratpack.service.Service; @@ -20,34 +18,41 @@ public class BarService implements Service { private final String url; - private final CountDownLatch latch; - private final Tracer tracer; + // private final CountDownLatch latch; + private final InstrumentationExtension testing; - public BarService(CountDownLatch latch, String url, OpenTelemetry openTelemetry) { - this.latch = latch; + public BarService(String url, InstrumentationExtension testing) { + // this.latch = latch; this.url = url; - this.tracer = openTelemetry.getTracerProvider().tracerBuilder("testing").build(); + this.testing = testing; } - @Override - public void onStart(StartEvent event) { + protected void generateSpan(StartEvent event) { Context parentContext = Context.current(); - Span span = tracer.spanBuilder("a-span").setParent(parentContext).startSpan(); + testing.runWithSpan( + "a-span", + () -> { + Span span = Span.current(); + Context otelContext = parentContext.with(span); + try (Scope scope = otelContext.makeCurrent()) { + Execution.current().add(Context.class, otelContext); + HttpClient httpClient = event.getRegistry().get(HttpClient.class); + httpClient + .get(new URI(url)) + .flatMap(response -> httpClient.get(new URI(url))) + .then( + response -> { + span.end(); + // latch.countDown(); + }); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + }); + } - Context otelContext = parentContext.with(span); - try (Scope scope = otelContext.makeCurrent()) { - Execution.current().add(Context.class, otelContext); - HttpClient httpClient = event.getRegistry().get(HttpClient.class); - httpClient - .get(new URI(url)) - .flatMap(response -> httpClient.get(new URI(url))) - .then( - response -> { - span.end(); - latch.countDown(); - }); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } + @Override + public void onStart(StartEvent event) { + generateSpan(event); } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java index 14c666365ea3..8e9fb7cb7dc9 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java @@ -5,41 +5,68 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.client; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.ErrorAttributes.ERROR_TYPE; import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; +import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; +import static io.opentelemetry.semconv.UrlAttributes.URL_QUERY; +import static io.opentelemetry.semconv.UrlAttributes.URL_SCHEME; import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Named.named; -import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.instrumentation.ratpack.v1_7.AbstractRatpackTest; -import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetry; +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import io.opentelemetry.sdk.trace.data.StatusData; import java.net.URI; import java.time.Duration; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import ratpack.exec.Promise; import ratpack.func.Action; import ratpack.guice.Guice; import ratpack.http.client.HttpClient; +import ratpack.http.client.HttpClientReadTimeoutException; +import ratpack.http.client.ReceivedResponse; import ratpack.test.embed.EmbeddedApp; -class InstrumentedHttpClientTest extends AbstractRatpackTest { +class InstrumentedHttpClientTest { + + @RegisterExtension + static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + + protected static final RatpackClientTelemetry clientTelemetry = + RatpackClientTelemetry.create(testing.getOpenTelemetry()); + + protected static final RatpackServerTelemetry serverTelemetry = + RatpackServerTelemetry.create(testing.getOpenTelemetry()); + + @RegisterExtension static final AutoCleanupExtension cleanup = AutoCleanupExtension.create(); @Test void testPropagateTraceWithHttpCalls() throws Exception { EmbeddedApp otherApp = EmbeddedApp.of( spec -> { - spec.registry( - Guice.registry(bindings -> serverTelemetry.configureRegistry(bindings))); + spec.registry(Guice.registry(serverTelemetry::configureRegistry)); spec.handlers(chain -> chain.get("bar", ctx -> ctx.render("foo"))); }); + cleanup.deferCleanup(otherApp); EmbeddedApp app = EmbeddedApp.of( @@ -49,7 +76,8 @@ void testPropagateTraceWithHttpCalls() throws Exception { bindings -> { serverTelemetry.configureRegistry(bindings); bindings.bindInstance( - HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); + HttpClient.class, + clientTelemetry.instrument(HttpClient.of(Action.noop()))); })); spec.handlers( @@ -59,53 +87,62 @@ void testPropagateTraceWithHttpCalls() throws Exception { ctx -> { HttpClient instrumentedHttpClient = ctx.get(HttpClient.class); instrumentedHttpClient - .get(new URI(otherApp.getAddress().toString() + "bar")) + .get(new URI(otherApp.getAddress() + "bar")) .then(response -> ctx.render("bar")); })); }); - - app.test( - httpClient -> { - assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("bar"); - - await() - .untilAsserted( - () -> { - SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); - SpanData spanClientData = findSpanData("GET", SpanKind.CLIENT); - SpanData spanDataApi = findSpanData("GET /bar", SpanKind.SERVER); - - assertThat(spanData.getTraceId()).isEqualTo(spanClientData.getTraceId()); - - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(spanClientData.getKind()).isEqualTo(SpanKind.CLIENT); - - Map, Object> clientAttributes = - spanClientData.getAttributes().asMap(); - assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/bar"); - assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - - Map, Object> attributes = spanData.getAttributes().asMap(); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - - Map, Object> apiAttributes = - spanDataApi.getAttributes().asMap(); - assertThat(apiAttributes.get(HTTP_ROUTE)).isEqualTo("/bar"); - assertThat(apiAttributes.get(URL_PATH)).isEqualTo("/bar"); - assertThat(apiAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(apiAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); - }); + cleanup.deferCleanup(app); + + assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("bar"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + equalTo(URL_QUERY, "")), + span -> + span.hasName("GET") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/bar"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo( + URL_FULL, + "http://localhost:" + otherApp.getServer().getBindPort() + "/bar")), + span -> + span.hasName("GET /bar") + .hasParent(trace.getSpan(1)) + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/bar"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + equalTo(SERVER_PORT, otherApp.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_PATH, "/bar"), + equalTo(URL_SCHEME, "http"), + equalTo(URL_QUERY, "")))); } @Test void testAddSpansForMultipleConcurrentClientCalls() throws Exception { - CountDownLatch latch = new CountDownLatch(2); - EmbeddedApp otherApp = EmbeddedApp.of( spec -> @@ -114,6 +151,7 @@ void testAddSpansForMultipleConcurrentClientCalls() throws Exception { chain.get("foo", ctx -> ctx.render("bar")); chain.get("bar", ctx -> ctx.render("foo")); })); + cleanup.deferCleanup(otherApp); EmbeddedApp app = EmbeddedApp.of( @@ -123,8 +161,10 @@ void testAddSpansForMultipleConcurrentClientCalls() throws Exception { bindings -> { serverTelemetry.configureRegistry(bindings); bindings.bindInstance( - HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); + HttpClient.class, + clientTelemetry.instrument(HttpClient.of(Action.noop()))); })); + spec.handlers( chain -> chain.get( @@ -132,82 +172,69 @@ void testAddSpansForMultipleConcurrentClientCalls() throws Exception { ctx -> { ctx.render("hello"); HttpClient instrumentedHttpClient = ctx.get(HttpClient.class); + instrumentedHttpClient - .get(new URI(otherApp.getAddress().toString() + "foo")) - .then(response -> latch.countDown()); + .get(new URI(otherApp.getAddress() + "foo")) + .then(ReceivedResponse::getBody); + instrumentedHttpClient - .get(new URI(otherApp.getAddress().toString() + "bar")) - .then(response -> latch.countDown()); + .get(new URI(otherApp.getAddress() + "bar")) + .then(ReceivedResponse::getBody); })); }); - - app.test( - httpClient -> { - assertThat(httpClient.get("path-name").getBody().getText()).isEqualTo("hello"); - latch.await(1, TimeUnit.SECONDS); - - await() - .untilAsserted( - () -> { - assertThat(spanExporter.getFinishedSpanItems().size()).isEqualTo(3); - - SpanData spanData = findSpanData("GET /path-name", SpanKind.SERVER); - - SpanData spanClientData1 = - spanExporter.getFinishedSpanItems().stream() - .filter( - span -> - "GET".equals(span.getName()) - && span.getAttributes() - .asMap() - .get(HTTP_ROUTE) - .equals("/foo")) - .findFirst() - .orElseThrow(() -> new AssertionError("Span not found")); - - SpanData spanClientData2 = - spanExporter.getFinishedSpanItems().stream() - .filter( - span -> - "GET".equals(span.getName()) - && span.getAttributes() - .asMap() - .get(HTTP_ROUTE) - .equals("/bar")) - .findFirst() - .orElseThrow(() -> new AssertionError("Span not found")); - - assertThat(spanData.getTraceId()).isEqualTo(spanClientData1.getTraceId()); - assertThat(spanData.getTraceId()).isEqualTo(spanClientData2.getTraceId()); - - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - - assertThat(spanClientData1.getKind()).isEqualTo(SpanKind.CLIENT); - Map, Object> clientAttributes = - spanClientData1.getAttributes().asMap(); - assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/foo"); - assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - - assertThat(spanClientData2.getKind()).isEqualTo(SpanKind.CLIENT); - Map, Object> client2Attributes = - spanClientData2.getAttributes().asMap(); - assertThat(client2Attributes.get(HTTP_ROUTE)).isEqualTo("/bar"); - assertThat(client2Attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(client2Attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - - Map, Object> attributes = spanData.getAttributes().asMap(); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/path-name"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/path-name"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); - }); + cleanup.deferCleanup(app); + + assertThat(app.getHttpClient().get("path-name").getBody().getText()).isEqualTo("hello"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /path-name") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/path-name"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + equalTo(URL_QUERY, ""), + equalTo(URL_PATH, "/path-name"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1")), + span -> + span.hasName("GET") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo( + URL_FULL, + "http://localhost:" + otherApp.getServer().getBindPort() + "/foo")), + span -> + span.hasName("GET") + .hasParent(trace.getSpan(0)) + .hasKind(SpanKind.CLIENT) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/bar"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo( + URL_FULL, + "http://localhost:" + + otherApp.getServer().getBindPort() + + "/bar")))); } @Test void testHandlingExceptionErrorsInHttpClient() throws Exception { - EmbeddedApp otherApp = EmbeddedApp.of( spec -> @@ -219,6 +246,7 @@ void testHandlingExceptionErrorsInHttpClient() throws Exception { Promise.value("bar") .defer(Duration.ofSeconds(1L)) .then(value -> ctx.render("bar"))))); + cleanup.deferCleanup(otherApp); EmbeddedApp app = EmbeddedApp.of( @@ -229,100 +257,74 @@ void testHandlingExceptionErrorsInHttpClient() throws Exception { serverTelemetry.configureRegistry(bindings); bindings.bindInstance( HttpClient.class, - telemetry.instrument( + clientTelemetry.instrument( HttpClient.of(s -> s.readTimeout(Duration.ofMillis(10))))); })); spec.handlers( chain -> chain.get( - "path-name", + "error-path-name", ctx -> { HttpClient instrumentedHttpClient = ctx.get(HttpClient.class); instrumentedHttpClient - .get(new URI(otherApp.getAddress().toString() + "foo")) + .get(new URI(otherApp.getAddress() + "foo")) .onError(throwable -> ctx.render("error")) .then(response -> ctx.render("hello")); })); }); - - app.test( - httpClient -> { - assertThat(httpClient.get("path-name").getBody().getText()).isEqualTo("error"); - - await() - .untilAsserted( - () -> { - SpanData spanData = findSpanData("GET /path-name", SpanKind.SERVER); - SpanData spanClientData = findSpanData("GET", SpanKind.CLIENT); - - assertThat(spanData.getTraceId()).isEqualTo(spanClientData.getTraceId()); - - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(spanClientData.getKind()).isEqualTo(SpanKind.CLIENT); - Map, Object> clientAttributes = - spanClientData.getAttributes().asMap(); - assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/foo"); - assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isNull(); - assertThat(spanClientData.getStatus().getStatusCode()) - .isEqualTo(StatusCode.ERROR); - assertThat(spanClientData.getEvents().stream().findFirst().get().getName()) - .isEqualTo("exception"); - - Map, Object> attributes = spanData.getAttributes().asMap(); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/path-name"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/path-name"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); - }); + cleanup.deferCleanup(app); + + assertThat(app.getHttpClient().get("error-path-name").getBody().getText()).isEqualTo("error"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /error-path-name") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/error-path-name"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_PATH, "/error-path-name"), + equalTo(URL_SCHEME, "http"), + equalTo(URL_QUERY, "")), + span -> + span.hasName("GET") + .hasKind(SpanKind.CLIENT) + .hasStatus(StatusData.error()) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(ERROR_TYPE, HttpClientReadTimeoutException.class.getName()), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo( + URL_FULL, + "http://localhost:" + + otherApp.getServer().getBindPort() + + "/foo")))); } - @Test - void testPropagateHttpTraceInRatpackServicesWithComputeThread() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - - EmbeddedApp otherApp = - EmbeddedApp.of(spec -> spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar")))); - - EmbeddedApp app = - EmbeddedApp.of( - spec -> { - spec.registry( - Guice.registry( - bindings -> { - serverTelemetry.configureRegistry(bindings); - bindings.bindInstance( - HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); - bindings.bindInstance( - new BarService( - latch, otherApp.getAddress().toString() + "foo", openTelemetry)); - })); - - spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar"))); - }); - - app.getAddress(); - latch.await(); - await() - .untilAsserted( - () -> { - SpanData spanData = findSpanData("a-span", SpanKind.INTERNAL); - assertThat( - spanExporter.getFinishedSpanItems().stream() - .filter(span -> span.getTraceId().equals(spanData.getTraceId())) - .count()) - .isEqualTo(3); - }); + private static Stream provideArguments() { + return Stream.of( + Arguments.of(named("Compute Thread", BarService.class)), + Arguments.of(named("Fork Executions", BarForkService.class))); } - @Test - void propagateHttpTraceInRatpackServicesWithForkExecutions() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - + @ParameterizedTest + @MethodSource("provideArguments") + void propagateHttpTraceInRatpackServicesWithForkExecutions( + Class serviceClass) throws Exception { EmbeddedApp otherApp = EmbeddedApp.of(spec -> spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar")))); + cleanup.deferCleanup(otherApp); EmbeddedApp app = EmbeddedApp.of( @@ -332,26 +334,51 @@ void propagateHttpTraceInRatpackServicesWithForkExecutions() throws Exception { bindings -> { serverTelemetry.configureRegistry(bindings); bindings.bindInstance( - HttpClient.class, telemetry.instrument(HttpClient.of(Action.noop()))); + HttpClient.class, + clientTelemetry.instrument(HttpClient.of(Action.noop()))); bindings.bindInstance( - new BarForkService( - latch, otherApp.getAddress().toString() + "foo", openTelemetry)); + serviceClass + .getConstructor(String.class, InstrumentationExtension.class) + .newInstance(otherApp.getAddress() + "foo", testing)); })); spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("bar"))); }); + cleanup.deferCleanup(app); app.getAddress(); - latch.await(); - await() - .untilAsserted( - () -> { - SpanData spanData = findSpanData("a-span", SpanKind.INTERNAL); - assertThat( - spanExporter.getFinishedSpanItems().stream() - .filter(span -> span.getTraceId().equals(spanData.getTraceId())) - .count()) - .isEqualTo(3); - }); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("a-span").hasNoParent().hasAttributes(Attributes.empty()), + span -> + span.hasName("GET") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo( + URL_FULL, + "http://localhost:" + otherApp.getServer().getBindPort() + "/foo")), + span -> + span.hasName("GET") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo( + URL_FULL, + "http://localhost:" + + otherApp.getServer().getBindPort() + + "/foo")))); } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java index 0102653459ec..a9f152da9c34 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/OpenTelemetryModule.java @@ -10,22 +10,23 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetry; import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; -import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; import javax.inject.Singleton; +import org.junit.jupiter.api.extension.RegisterExtension; import ratpack.exec.ExecInitializer; import ratpack.exec.ExecInterceptor; -import ratpack.func.Action; import ratpack.handling.Handler; import ratpack.http.client.HttpClient; public class OpenTelemetryModule extends AbstractModule { + + @RegisterExtension + static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + @Override protected void configure() { - bind(SpanExporter.class).toInstance(InMemorySpanExporter.create()); + bind(OpenTelemetry.class).toInstance(testing.getOpenTelemetry()); } @Singleton @@ -52,20 +53,10 @@ ExecInterceptor ratpackExecInterceptor(RatpackServerTelemetry ratpackTracing) { return ratpackTracing.getExecInterceptor(); } - @Provides - @Singleton - OpenTelemetry providesOpenTelemetry(SpanExporter spanExporter) { - SdkTracerProvider tracerProvider = - SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build(); - return OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); - } - @Singleton @Provides HttpClient instrumentedHttpClient(RatpackClientTelemetry ratpackTracing) throws Exception { - return ratpackTracing.instrument(HttpClient.of(Action.noop())); + return ratpackTracing.instrument(HttpClient.of(spec -> {})); } @Singleton diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java index ac73972fd063..71738c82a57f 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java @@ -12,6 +12,9 @@ import ratpack.server.RatpackServer; public class RatpackApp { + + private RatpackApp() {} + public static void main(String... args) throws Exception { RatpackServer.start( server -> @@ -30,6 +33,4 @@ public static void main(String... args) throws Exception { .get(ctx.get(URI.class)) .then(response -> ctx.render("hi-bar"))))); } - - private RatpackApp() {} } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java index 246511c498d4..9f367a528adf 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackFunctionalTest.java @@ -5,43 +5,33 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server; -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; -import io.opentelemetry.sdk.trace.export.SpanExporter; import java.net.URI; import ratpack.guice.BindingsImposition; import ratpack.impose.ForceDevelopmentImposition; import ratpack.impose.ImpositionsSpec; -import ratpack.impose.UserRegistryImposition; -import ratpack.registry.Registry; import ratpack.test.MainClassApplicationUnderTest; import ratpack.test.embed.EmbeddedApp; public class RatpackFunctionalTest extends MainClassApplicationUnderTest { - private Registry registry; - protected InMemorySpanExporter spanExporter; - private final EmbeddedApp app; + private final EmbeddedApp app = + EmbeddedApp.of( + server -> server.handlers(chain -> chain.get("other", ctx -> ctx.render("hi-other")))); public RatpackFunctionalTest(Class mainClass) throws Exception { super(mainClass); - this.app = - EmbeddedApp.of( - server -> server.handlers(chain -> chain.get("other", ctx -> ctx.render("hi-other")))); getAddress(); } @Override protected void addImpositions(ImpositionsSpec impositions) { impositions.add(ForceDevelopmentImposition.of(false)); - impositions.add( - UserRegistryImposition.of( - r -> { - registry = r; - spanExporter = (InMemorySpanExporter) registry.get(SpanExporter.class); - return registry; - })); impositions.add( BindingsImposition.of( bindings -> bindings.bindInstance(URI.class, app.getAddress().resolve("other")))); } + + public int getAppPort() { + return app.getServer().getBindPort(); + } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java index 54106f7361e7..6559b6cb60c3 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java @@ -5,88 +5,95 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; +import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; +import static io.opentelemetry.semconv.UrlAttributes.URL_QUERY; +import static io.opentelemetry.semconv.UrlAttributes.URL_SCHEME; import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.sdk.trace.data.SpanData; -import java.util.Map; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; class RatpackServerApplicationTest { + @RegisterExtension + static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); - private final RatpackFunctionalTest app = new RatpackFunctionalTest(RatpackApp.class); + private static RatpackFunctionalTest app; + + @BeforeAll + static void setup() throws Exception { + app = new RatpackFunctionalTest(RatpackApp.class); + } @Test void testAddSpanOnHandlers() throws Exception { app.test( - httpClient -> { - assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - - await() - .untilAsserted( - () -> { - SpanData spanData = - app.spanExporter.getFinishedSpanItems().stream() - .filter(span -> "GET /foo".equals(span.getName())) - .findFirst() - .orElseThrow(() -> new AssertionError("Span not found")); - - Map, Object> attributes = spanData.getAttributes().asMap(); - - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); - }); + httpClient -> assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo")); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)))); } @Test void testPropagateTraceToHttpCalls() throws Exception { app.test( - httpClient -> { - assertThat(httpClient.get("bar").getBody().getText()).isEqualTo("hi-bar"); - - await() - .untilAsserted( - () -> { - SpanData spanData = - app.spanExporter.getFinishedSpanItems().stream() - .filter(span -> "GET /bar".equals(span.getName())) - .findFirst() - .orElseThrow(() -> new AssertionError("Span not found")); - - SpanData spanDataClient = - app.spanExporter.getFinishedSpanItems().stream() - .filter(span -> span.getName().equals("GET")) - .findFirst() - .orElseThrow(() -> new AssertionError("Span not found")); - - assertThat(spanData.getTraceId()).isEqualTo(spanDataClient.getTraceId()); - - Map, Object> attributes = spanData.getAttributes().asMap(); - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/bar"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/bar"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - - Map, Object> clientAttributes = - spanDataClient.getAttributes().asMap(); - - assertThat(spanDataClient.getKind()).isEqualTo(SpanKind.CLIENT); - assertThat(clientAttributes.get(HTTP_ROUTE)).isEqualTo("/other"); - assertThat(clientAttributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(clientAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); - }); + httpClient -> assertThat(httpClient.get("bar").getBody().getText()).isEqualTo("hi-bar")); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /bar") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/bar"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + equalTo(URL_PATH, "/bar"), + equalTo(URL_SCHEME, "http"), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, "")), + span -> + span.hasName("GET") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/other"), + equalTo(URL_FULL, "http://localhost:" + app.getAppPort() + "/other"), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), + satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), + equalTo(SERVER_ADDRESS, "localhost")))); } @Test @@ -94,16 +101,8 @@ void testIgnoreHandlersBeforeOpenTelemetryServerHandler() throws Exception { app.test( httpClient -> { assertThat(httpClient.get("ignore").getBody().getText()).isEqualTo("ignored"); - - await() - .untilAsserted( - () -> - assertThat( - app.spanExporter.getFinishedSpanItems().stream() - .noneMatch(span -> "GET /ignore".equals(span.getName()))) - .isTrue()); + assertThat(testing.spans().stream().filter(span -> "GET /ignore".equals(span.getName()))) + .isEmpty(); }); } - - RatpackServerApplicationTest() throws Exception {} } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java index faedec80ee43..8beba03df677 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java @@ -5,34 +5,50 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; +import static io.opentelemetry.semconv.UrlAttributes.URL_QUERY; +import static io.opentelemetry.semconv.UrlAttributes.URL_SCHEME; import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; -import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.ratpack.v1_7.AbstractRatpackTest; -import io.opentelemetry.sdk.trace.data.SpanData; -import java.util.Map; +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import ratpack.exec.Blocking; import ratpack.registry.Registry; import ratpack.test.embed.EmbeddedApp; -class RatpackServerTest extends AbstractRatpackTest { +class RatpackServerTest { + @RegisterExtension + static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + + static Registry registry; + static RatpackServerTelemetry telemetry = + RatpackServerTelemetry.builder(testing.getOpenTelemetry()).build(); + + @BeforeAll + static void setUp() throws Exception { + registry = Registry.of(telemetry::configureRegistry); + } @Test void testAddSpanOnHandlers() throws Exception { EmbeddedApp app = EmbeddedApp.of( spec -> { - spec.registry( - registry -> Registry.of(regSpec -> serverTelemetry.configureRegistry(regSpec))); + spec.registry(registry); spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("hi-foo"))); }); @@ -40,18 +56,23 @@ void testAddSpanOnHandlers() throws Exception { httpClient -> { assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - await() - .untilAsserted( - () -> { - SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); - Map, Object> attributes = spanData.getAttributes().asMap(); - - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)))); }); } @@ -60,8 +81,7 @@ void testPropagateTraceWithInstrumentedAsyncOperations() throws Exception { EmbeddedApp app = EmbeddedApp.of( spec -> { - spec.registry( - registry -> Registry.of(regSpec -> serverTelemetry.configureRegistry(regSpec))); + spec.registry(registry); spec.handlers( chain -> chain.get( @@ -69,18 +89,13 @@ void testPropagateTraceWithInstrumentedAsyncOperations() throws Exception { ctx -> { ctx.render("hi-foo"); Blocking.op( - () -> { - Span span = - openTelemetry - .getTracer("any-tracer") - .spanBuilder("a-span") - .startSpan(); - try (Scope scope = span.makeCurrent()) { - span.addEvent("an-event"); - } finally { - span.end(); - } - }) + () -> + testing.runWithSpan( + "a-span", + () -> { + Span span = Span.current(); + span.addEvent("an-event"); + })) .then(); })); }); @@ -89,27 +104,28 @@ void testPropagateTraceWithInstrumentedAsyncOperations() throws Exception { httpClient -> { assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - await() - .untilAsserted( - () -> { - SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); - SpanData spanDataChild = findSpanData("a-span", SpanKind.INTERNAL); - - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(spanData.getTraceId()).isEqualTo(spanDataChild.getTraceId()); - assertThat(spanDataChild.getParentSpanId()).isEqualTo(spanData.getSpanId()); - assertThat( - spanDataChild.getEvents().stream() - .filter(event -> "an-event".equals(event.getName())) - .count()) - .isEqualTo(1); - - Map, Object> attributes = spanData.getAttributes().asMap(); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), + span -> + span.hasName("a-span") + .hasParent(trace.getSpan(0)) + .hasAttributes(Attributes.empty()) + .hasTotalRecordedEvents(1))); }); } @@ -118,8 +134,7 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except EmbeddedApp app = EmbeddedApp.of( spec -> { - spec.registry( - registry -> Registry.of(regSpec -> serverTelemetry.configureRegistry(regSpec))); + spec.registry(registry); spec.handlers( chain -> { chain.get( @@ -127,18 +142,13 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except ctx -> { ctx.render("hi-bar"); Blocking.op( - () -> { - Span span = - openTelemetry - .getTracer("any-tracer") - .spanBuilder("another-span") - .startSpan(); - try (Scope scope = span.makeCurrent()) { - span.addEvent("an-event"); - } finally { - span.end(); - } - }) + () -> + testing.runWithSpan( + "another-span", + () -> { + Span span = Span.current(); + span.addEvent("an-event"); + })) .then(); }); chain.get( @@ -146,18 +156,13 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except ctx -> { ctx.render("hi-foo"); Blocking.op( - () -> { - Span span = - openTelemetry - .getTracer("any-tracer") - .spanBuilder("a-span") - .startSpan(); - try (Scope scope = span.makeCurrent()) { - span.addEvent("an-event"); - } finally { - span.end(); - } - }) + () -> + testing.runWithSpan( + "a-span", + () -> { + Span span = Span.current(); + span.addEvent("an-event"); + })) .then(); }); }); @@ -168,38 +173,49 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); assertThat(httpClient.get("bar").getBody().getText()).isEqualTo("hi-bar"); - await() - .untilAsserted( - () -> { - SpanData spanData = findSpanData("GET /foo", SpanKind.SERVER); - SpanData spanDataChild = findSpanData("a-span", SpanKind.INTERNAL); - SpanData spanData2 = findSpanData("GET /bar", SpanKind.SERVER); - SpanData spanDataChild2 = findSpanData("another-span", SpanKind.INTERNAL); - - assertThat(spanData.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(spanData.getTraceId()).isEqualTo(spanDataChild.getTraceId()); - assertThat(spanDataChild.getParentSpanId()).isEqualTo(spanData.getSpanId()); - assertThat( - spanDataChild.getEvents().stream() - .filter(event -> "an-event".equals(event.getName())) - .count()) - .isEqualTo(1); - - assertThat(spanData2.getKind()).isEqualTo(SpanKind.SERVER); - assertThat(spanData2.getTraceId()).isEqualTo(spanDataChild2.getTraceId()); - assertThat(spanDataChild2.getParentSpanId()).isEqualTo(spanData2.getSpanId()); - assertThat( - spanDataChild2.getEvents().stream() - .filter(event -> "an-event".equals(event.getName())) - .count()) - .isEqualTo(1); - - Map, Object> attributes = spanData.getAttributes().asMap(); - assertThat(attributes.get(HTTP_ROUTE)).isEqualTo("/foo"); - assertThat(attributes.get(URL_PATH)).isEqualTo("/foo"); - assertThat(attributes.get(HTTP_REQUEST_METHOD)).isEqualTo("GET"); - assertThat(attributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(200L); - }); + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), + span -> + span.hasName("a-span") + .hasParent(trace.getSpan(0)) + .hasAttributes(Attributes.empty()) + .hasTotalRecordedEvents(1)), + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /bar") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/bar"), + equalTo(URL_PATH, "/bar"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), + span -> + span.hasName("another-span") + .hasParent(trace.getSpan(0)) + .hasAttributes(Attributes.empty()) + .hasTotalRecordedEvents(1))); }); } } From 6d6a93f66f84fc1dc5f044331aa0286425d4b29d Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Sat, 4 Jan 2025 07:57:25 -0500 Subject: [PATCH 5/9] cleanups --- .../ratpack/v1_7/client/BarService.java | 3 - .../client/InstrumentedHttpClientTest.java | 11 +- .../ratpack/v1_7/server/RatpackApp.java | 4 +- .../server/RatpackServerApplicationTest.java | 23 +-- .../v1_7/server/RatpackServerTest.java | 194 +++++++++--------- 5 files changed, 110 insertions(+), 125 deletions(-) diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java index faab66db485b..b5b612d3f6e1 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java @@ -18,11 +18,9 @@ public class BarService implements Service { private final String url; - // private final CountDownLatch latch; private final InstrumentationExtension testing; public BarService(String url, InstrumentationExtension testing) { - // this.latch = latch; this.url = url; this.testing = testing; } @@ -43,7 +41,6 @@ protected void generateSpan(StartEvent event) { .then( response -> { span.end(); - // latch.countDown(); }); } catch (URISyntaxException e) { throw new RuntimeException(e); diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java index 8e9fb7cb7dc9..6143ff2cb057 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java @@ -48,16 +48,17 @@ class InstrumentedHttpClientTest { @RegisterExtension - static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + private static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); - protected static final RatpackClientTelemetry clientTelemetry = + @RegisterExtension + private static final AutoCleanupExtension cleanup = AutoCleanupExtension.create(); + + private static final RatpackClientTelemetry clientTelemetry = RatpackClientTelemetry.create(testing.getOpenTelemetry()); - protected static final RatpackServerTelemetry serverTelemetry = + private static final RatpackServerTelemetry serverTelemetry = RatpackServerTelemetry.create(testing.getOpenTelemetry()); - @RegisterExtension static final AutoCleanupExtension cleanup = AutoCleanupExtension.create(); - @Test void testPropagateTraceWithHttpCalls() throws Exception { EmbeddedApp otherApp = diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java index 71738c82a57f..92eee76a3a94 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackApp.java @@ -13,8 +13,6 @@ public class RatpackApp { - private RatpackApp() {} - public static void main(String... args) throws Exception { RatpackServer.start( server -> @@ -33,4 +31,6 @@ public static void main(String... args) throws Exception { .get(ctx.get(URI.class)) .then(response -> ctx.render("hi-bar"))))); } + + private RatpackApp() {} } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java index 6559b6cb60c3..0e506c578d84 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java @@ -28,7 +28,7 @@ class RatpackServerApplicationTest { @RegisterExtension - static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + private static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); private static RatpackFunctionalTest app; @@ -38,9 +38,8 @@ static void setup() throws Exception { } @Test - void testAddSpanOnHandlers() throws Exception { - app.test( - httpClient -> assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo")); + void testAddSpanOnHandlers() { + assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); testing.waitAndAssertTraces( trace -> @@ -62,9 +61,8 @@ void testAddSpanOnHandlers() throws Exception { } @Test - void testPropagateTraceToHttpCalls() throws Exception { - app.test( - httpClient -> assertThat(httpClient.get("bar").getBody().getText()).isEqualTo("hi-bar")); + void testPropagateTraceToHttpCalls() { + assertThat(app.getHttpClient().get("bar").getBody().getText()).isEqualTo("hi-bar"); testing.waitAndAssertTraces( trace -> @@ -97,12 +95,9 @@ void testPropagateTraceToHttpCalls() throws Exception { } @Test - void testIgnoreHandlersBeforeOpenTelemetryServerHandler() throws Exception { - app.test( - httpClient -> { - assertThat(httpClient.get("ignore").getBody().getText()).isEqualTo("ignored"); - assertThat(testing.spans().stream().filter(span -> "GET /ignore".equals(span.getName()))) - .isEmpty(); - }); + void testIgnoreHandlersBeforeOpenTelemetryServerHandler() { + assertThat(app.getHttpClient().get("ignore").getBody().getText()).isEqualTo("ignored"); + assertThat(testing.spans().stream().filter(span -> "GET /ignore".equals(span.getName()))) + .isEmpty(); } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java index 8beba03df677..c13eebb2ee1e 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java @@ -32,12 +32,13 @@ class RatpackServerTest { @RegisterExtension - static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + private static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); - static Registry registry; - static RatpackServerTelemetry telemetry = + private static final RatpackServerTelemetry telemetry = RatpackServerTelemetry.builder(testing.getOpenTelemetry()).build(); + private static Registry registry; + @BeforeAll static void setUp() throws Exception { registry = Registry.of(telemetry::configureRegistry); @@ -52,28 +53,25 @@ void testAddSpanOnHandlers() throws Exception { spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("hi-foo"))); }); - app.test( - httpClient -> { - assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - - testing.waitAndAssertTraces( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /foo") - .hasNoParent() - .hasKind(SpanKind.SERVER) - .hasAttributesSatisfyingExactly( - equalTo(HTTP_ROUTE, "/foo"), - equalTo(URL_PATH, "/foo"), - equalTo(URL_SCHEME, "http"), - equalTo(SERVER_PORT, app.getServer().getBindPort()), - equalTo(SERVER_ADDRESS, "localhost"), - equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), - equalTo(URL_QUERY, ""), - equalTo(HTTP_REQUEST_METHOD, "GET"), - equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)))); - }); + assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)))); } @Test @@ -100,33 +98,30 @@ void testPropagateTraceWithInstrumentedAsyncOperations() throws Exception { })); }); - app.test( - httpClient -> { - assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - - testing.waitAndAssertTraces( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /foo") - .hasNoParent() - .hasKind(SpanKind.SERVER) - .hasAttributesSatisfyingExactly( - equalTo(HTTP_ROUTE, "/foo"), - equalTo(URL_PATH, "/foo"), - equalTo(URL_SCHEME, "http"), - equalTo(SERVER_PORT, app.getServer().getBindPort()), - equalTo(SERVER_ADDRESS, "localhost"), - equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), - equalTo(URL_QUERY, ""), - equalTo(HTTP_REQUEST_METHOD, "GET"), - equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), - span -> - span.hasName("a-span") - .hasParent(trace.getSpan(0)) - .hasAttributes(Attributes.empty()) - .hasTotalRecordedEvents(1))); - }); + assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), + span -> + span.hasName("a-span") + .hasParent(trace.getSpan(0)) + .hasAttributes(Attributes.empty()) + .hasTotalRecordedEvents(1))); } @Test @@ -168,54 +163,51 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except }); }); - app.test( - httpClient -> { - assertThat(httpClient.get("foo").getBody().getText()).isEqualTo("hi-foo"); - assertThat(httpClient.get("bar").getBody().getText()).isEqualTo("hi-bar"); - - testing.waitAndAssertTraces( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /foo") - .hasNoParent() - .hasKind(SpanKind.SERVER) - .hasAttributesSatisfyingExactly( - equalTo(HTTP_ROUTE, "/foo"), - equalTo(URL_PATH, "/foo"), - equalTo(URL_SCHEME, "http"), - equalTo(SERVER_PORT, app.getServer().getBindPort()), - equalTo(SERVER_ADDRESS, "localhost"), - equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), - equalTo(URL_QUERY, ""), - equalTo(HTTP_REQUEST_METHOD, "GET"), - equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), - span -> - span.hasName("a-span") - .hasParent(trace.getSpan(0)) - .hasAttributes(Attributes.empty()) - .hasTotalRecordedEvents(1)), - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /bar") - .hasNoParent() - .hasKind(SpanKind.SERVER) - .hasAttributesSatisfyingExactly( - equalTo(HTTP_ROUTE, "/bar"), - equalTo(URL_PATH, "/bar"), - equalTo(URL_SCHEME, "http"), - equalTo(SERVER_PORT, app.getServer().getBindPort()), - equalTo(SERVER_ADDRESS, "localhost"), - equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), - equalTo(URL_QUERY, ""), - equalTo(HTTP_REQUEST_METHOD, "GET"), - equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), - span -> - span.hasName("another-span") - .hasParent(trace.getSpan(0)) - .hasAttributes(Attributes.empty()) - .hasTotalRecordedEvents(1))); - }); + assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); + assertThat(app.getHttpClient().get("bar").getBody().getText()).isEqualTo("hi-bar"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /foo") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/foo"), + equalTo(URL_PATH, "/foo"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), + span -> + span.hasName("a-span") + .hasParent(trace.getSpan(0)) + .hasAttributes(Attributes.empty()) + .hasTotalRecordedEvents(1)), + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /bar") + .hasNoParent() + .hasKind(SpanKind.SERVER) + .hasAttributesSatisfyingExactly( + equalTo(HTTP_ROUTE, "/bar"), + equalTo(URL_PATH, "/bar"), + equalTo(URL_SCHEME, "http"), + equalTo(SERVER_PORT, app.getServer().getBindPort()), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), + equalTo(URL_QUERY, ""), + equalTo(HTTP_REQUEST_METHOD, "GET"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200L)), + span -> + span.hasName("another-span") + .hasParent(trace.getSpan(0)) + .hasAttributes(Attributes.empty()) + .hasTotalRecordedEvents(1))); } } From 546afe36e9ee1f582ad80edccec1d730ac54e2b9 Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Sat, 4 Jan 2025 08:01:07 -0500 Subject: [PATCH 6/9] cleanups --- .../instrumentation/ratpack/v1_7/client/BarService.java | 5 +---- .../ratpack/v1_7/server/RatpackServerTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java index b5b612d3f6e1..80ea6133259f 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/BarService.java @@ -38,10 +38,7 @@ protected void generateSpan(StartEvent event) { httpClient .get(new URI(url)) .flatMap(response -> httpClient.get(new URI(url))) - .then( - response -> { - span.end(); - }); + .then(response -> span.end()); } catch (URISyntaxException e) { throw new RuntimeException(e); } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java index c13eebb2ee1e..3d7b7b2f4af8 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java @@ -21,6 +21,7 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry; +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; import org.junit.jupiter.api.BeforeAll; @@ -34,6 +35,9 @@ class RatpackServerTest { @RegisterExtension private static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + @RegisterExtension + private static final AutoCleanupExtension cleanup = AutoCleanupExtension.create(); + private static final RatpackServerTelemetry telemetry = RatpackServerTelemetry.builder(testing.getOpenTelemetry()).build(); @@ -52,6 +56,7 @@ void testAddSpanOnHandlers() throws Exception { spec.registry(registry); spec.handlers(chain -> chain.get("foo", ctx -> ctx.render("hi-foo"))); }); + cleanup.deferCleanup(app); assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); @@ -97,6 +102,7 @@ void testPropagateTraceWithInstrumentedAsyncOperations() throws Exception { .then(); })); }); + cleanup.deferCleanup(app); assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); @@ -162,6 +168,7 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except }); }); }); + cleanup.deferCleanup(app); assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); assertThat(app.getHttpClient().get("bar").getBody().getText()).isEqualTo("hi-bar"); From fa7eca6f0d474e0006add2e7ac71c5332a10e11e Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Sat, 4 Jan 2025 08:12:18 -0500 Subject: [PATCH 7/9] cleanups --- .../client/InstrumentedHttpClientTest.java | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java index 6143ff2cb057..5d333e810448 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java @@ -123,9 +123,7 @@ void testPropagateTraceWithHttpCalls() throws Exception { equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo( - URL_FULL, - "http://localhost:" + otherApp.getServer().getBindPort() + "/bar")), + equalTo(URL_FULL, otherApp.getAddress() + "/bar")), span -> span.hasName("GET /bar") .hasParent(trace.getSpan(1)) @@ -214,9 +212,7 @@ void testAddSpansForMultipleConcurrentClientCalls() throws Exception { equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo( - URL_FULL, - "http://localhost:" + otherApp.getServer().getBindPort() + "/foo")), + equalTo(URL_FULL, otherApp.getAddress() + "/foo")), span -> span.hasName("GET") .hasParent(trace.getSpan(0)) @@ -227,11 +223,7 @@ void testAddSpansForMultipleConcurrentClientCalls() throws Exception { equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo( - URL_FULL, - "http://localhost:" - + otherApp.getServer().getBindPort() - + "/bar")))); + equalTo(URL_FULL, otherApp.getAddress() + "/bar")))); } @Test @@ -306,11 +298,7 @@ void testHandlingExceptionErrorsInHttpClient() throws Exception { equalTo(ERROR_TYPE, HttpClientReadTimeoutException.class.getName()), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo( - URL_FULL, - "http://localhost:" - + otherApp.getServer().getBindPort() - + "/foo")))); + equalTo(URL_FULL, otherApp.getAddress() + "/foo")))); } private static Stream provideArguments() { @@ -363,9 +351,7 @@ void propagateHttpTraceInRatpackServicesWithForkExecutions( equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo( - URL_FULL, - "http://localhost:" + otherApp.getServer().getBindPort() + "/foo")), + equalTo(URL_FULL, otherApp.getAddress() + "foo")), span -> span.hasName("GET") .hasKind(SpanKind.CLIENT) @@ -376,10 +362,6 @@ void propagateHttpTraceInRatpackServicesWithForkExecutions( equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo( - URL_FULL, - "http://localhost:" - + otherApp.getServer().getBindPort() - + "/foo")))); + equalTo(URL_FULL, otherApp.getAddress() + "foo")))); } } From 0490ecdba50f7114f14b9fb07c43bf0efb88dd78 Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Sat, 4 Jan 2025 08:28:06 -0500 Subject: [PATCH 8/9] fix slash --- .../ratpack/v1_7/client/InstrumentedHttpClientTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java index 5d333e810448..dbac9f36b6e4 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.java @@ -123,7 +123,7 @@ void testPropagateTraceWithHttpCalls() throws Exception { equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo(URL_FULL, otherApp.getAddress() + "/bar")), + equalTo(URL_FULL, otherApp.getAddress() + "bar")), span -> span.hasName("GET /bar") .hasParent(trace.getSpan(1)) @@ -212,7 +212,7 @@ void testAddSpansForMultipleConcurrentClientCalls() throws Exception { equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo(URL_FULL, otherApp.getAddress() + "/foo")), + equalTo(URL_FULL, otherApp.getAddress() + "foo")), span -> span.hasName("GET") .hasParent(trace.getSpan(0)) @@ -223,7 +223,7 @@ void testAddSpansForMultipleConcurrentClientCalls() throws Exception { equalTo(HTTP_RESPONSE_STATUS_CODE, 200L), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo(URL_FULL, otherApp.getAddress() + "/bar")))); + equalTo(URL_FULL, otherApp.getAddress() + "bar")))); } @Test @@ -298,7 +298,7 @@ void testHandlingExceptionErrorsInHttpClient() throws Exception { equalTo(ERROR_TYPE, HttpClientReadTimeoutException.class.getName()), satisfies(SERVER_PORT, v -> v.isInstanceOf(Long.class)), equalTo(SERVER_ADDRESS, "localhost"), - equalTo(URL_FULL, otherApp.getAddress() + "/foo")))); + equalTo(URL_FULL, otherApp.getAddress() + "foo")))); } private static Stream provideArguments() { From af41bc7e742930e5c7210ee6c2ca49629eb64335 Mon Sep 17 00:00:00 2001 From: Jay DeLuca Date: Mon, 6 Jan 2025 20:45:02 -0500 Subject: [PATCH 9/9] add app cleanup, assert events, rewrite test to use waitAndAssertTraces --- .../server/RatpackServerApplicationTest.java | 23 ++++++++++++++++--- .../v1_7/server/RatpackServerTest.java | 9 +++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java index 0e506c578d84..df83b1580b95 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.java @@ -19,9 +19,11 @@ import static io.opentelemetry.semconv.UrlAttributes.URL_SCHEME; import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -37,6 +39,11 @@ static void setup() throws Exception { app = new RatpackFunctionalTest(RatpackApp.class); } + @AfterAll + static void cleanup() { + app.close(); + } + @Test void testAddSpanOnHandlers() { assertThat(app.getHttpClient().get("foo").getBody().getText()).isEqualTo("hi-foo"); @@ -96,8 +103,18 @@ void testPropagateTraceToHttpCalls() { @Test void testIgnoreHandlersBeforeOpenTelemetryServerHandler() { - assertThat(app.getHttpClient().get("ignore").getBody().getText()).isEqualTo("ignored"); - assertThat(testing.spans().stream().filter(span -> "GET /ignore".equals(span.getName()))) - .isEmpty(); + testing.runWithSpan( + "parent", + () -> + assertThat(app.getHttpClient().get("ignore").getBody().getText()).isEqualTo("ignored")); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasNoParent() + .hasKind(SpanKind.INTERNAL) + .hasAttributes(Attributes.empty()))); } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java index 3d7b7b2f4af8..ac8253b09841 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.java @@ -127,7 +127,8 @@ void testPropagateTraceWithInstrumentedAsyncOperations() throws Exception { span.hasName("a-span") .hasParent(trace.getSpan(0)) .hasAttributes(Attributes.empty()) - .hasTotalRecordedEvents(1))); + .hasEventsSatisfyingExactly( + event -> event.hasName("an-event").hasAttributes(Attributes.empty())))); } @Test @@ -194,7 +195,8 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except span.hasName("a-span") .hasParent(trace.getSpan(0)) .hasAttributes(Attributes.empty()) - .hasTotalRecordedEvents(1)), + .hasEventsSatisfyingExactly( + event -> event.hasName("an-event").hasAttributes(Attributes.empty()))), trace -> trace.hasSpansSatisfyingExactly( span -> @@ -215,6 +217,7 @@ void testPropagateTraceWithInstrumentedAsyncConcurrentOperations() throws Except span.hasName("another-span") .hasParent(trace.getSpan(0)) .hasAttributes(Attributes.empty()) - .hasTotalRecordedEvents(1))); + .hasEventsSatisfyingExactly( + event -> event.hasName("an-event").hasAttributes(Attributes.empty())))); } }