diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java index b5b404f9f8120..350a89459e648 100644 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java +++ b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java @@ -282,8 +282,10 @@ void setupVertx(InstrumentationRecorder recorder, BeanContainerBuildItem beanCon || capabilities.isPresent(Capability.REACTIVE_MYSQL_CLIENT) || capabilities.isPresent(Capability.REACTIVE_ORACLE_CLIENT) || capabilities.isPresent(Capability.REACTIVE_PG_CLIENT); + boolean redisClientAvailable = capabilities.isPresent(Capability.REDIS_CLIENT); recorder.setupVertxTracer(beanContainerBuildItem.getValue(), sqlClientAvailable, + redisClientAvailable, ConfigProvider.getConfig() .getConfigValue(QUARKUS_OTEL_SEMCONV_STABILITY_OPT_IN) .getValue()); diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/InstrumentRuntimeConfig.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/InstrumentRuntimeConfig.java index f5c5cdddd104b..c781da7e17717 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/InstrumentRuntimeConfig.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/InstrumentRuntimeConfig.java @@ -24,4 +24,10 @@ public interface InstrumentRuntimeConfig { @WithDefault("true") boolean vertxSqlClient(); + /** + * Enables instrumentation for Vert.x Redis Client. + */ + @WithDefault("true") + boolean vertxRedisClient(); + } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java index f155facf34c8a..debb921c7350b 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java @@ -15,6 +15,7 @@ import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxMetricsFactory; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracer; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracingFactory; +import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.RedisClientInstrumenterVertxTracer; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.SqlClientInstrumenterVertxTracer; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; @@ -42,9 +43,9 @@ public Consumer getVertxTracingOptions() { /* RUNTIME INIT */ public void setupVertxTracer(BeanContainer beanContainer, boolean sqlClientAvailable, - final String semconvStability) { + boolean redisClientAvailable, final String semconvStability) { OpenTelemetry openTelemetry = beanContainer.beanInstance(OpenTelemetry.class); - List> tracers = new ArrayList<>(3); + List> tracers = new ArrayList<>(4); if (config.getValue().instrument().vertxHttp()) { tracers.add(new HttpInstrumenterVertxTracer(openTelemetry, getSemconvStabilityOptin(semconvStability))); } @@ -54,6 +55,9 @@ public void setupVertxTracer(BeanContainer beanContainer, boolean sqlClientAvail if (sqlClientAvailable && config.getValue().instrument().vertxSqlClient()) { tracers.add(new SqlClientInstrumenterVertxTracer(openTelemetry)); } + if (redisClientAvailable && config.getValue().instrument().vertxRedisClient()) { + tracers.add(new RedisClientInstrumenterVertxTracer(openTelemetry)); + } OpenTelemetryVertxTracer openTelemetryVertxTracer = new OpenTelemetryVertxTracer(tracers); FACTORY.getVertxTracerDelegator().setDelegate(openTelemetryVertxTracer); } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/RedisClientInstrumenterVertxTracer.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/RedisClientInstrumenterVertxTracer.java new file mode 100644 index 0000000000000..6c9d98bb259e1 --- /dev/null +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/RedisClientInstrumenterVertxTracer.java @@ -0,0 +1,174 @@ +package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx; + +import static io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig.INSTRUMENTATION_NAME; + +import java.util.Map; +import java.util.function.BiConsumer; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesGetter; +import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor; +import io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil; +import io.opentelemetry.semconv.SemanticAttributes; +import io.vertx.core.Context; +import io.vertx.core.spi.tracing.SpanKind; +import io.vertx.core.spi.tracing.TagExtractor; +import io.vertx.core.tracing.TracingPolicy; + +public class RedisClientInstrumenterVertxTracer implements + InstrumenterVertxTracer { + private final Instrumenter redisClientInstrumenter; + + public RedisClientInstrumenterVertxTracer(final OpenTelemetry openTelemetry) { + InstrumenterBuilder clientInstrumenterBuilder = Instrumenter.builder( + openTelemetry, + INSTRUMENTATION_NAME, + DbClientSpanNameExtractor.create(RedisClientAttributesGetter.INSTANCE)); + + this.redisClientInstrumenter = clientInstrumenterBuilder + .addAttributesExtractor(DbClientAttributesExtractor.create(RedisClientAttributesGetter.INSTANCE)) + .addAttributesExtractor(RedisClientAttributesExtractor.INSTANCE) + .buildInstrumenter(SpanKindExtractor.alwaysClient()); + } + + @Override + public boolean canHandle(R request, TagExtractor tagExtractor) { + if (request instanceof CommandTrace) { + return true; + } + + return "redis".equals(tagExtractor.extract(request).get("db.type")); + } + + @Override + @SuppressWarnings("unchecked") + public OpenTelemetryVertxTracer.SpanOperation sendRequest( + final Context context, + final SpanKind kind, + final TracingPolicy policy, + final R request, + final String operation, + final BiConsumer headers, + final TagExtractor tagExtractor) { + R commandTrace = (R) CommandTrace.commandTrace(tagExtractor.extract(request)); + return InstrumenterVertxTracer.super.sendRequest(context, kind, policy, commandTrace, operation, headers, tagExtractor); + } + + @Override + public void receiveResponse( + final Context context, + final R response, + final OpenTelemetryVertxTracer.SpanOperation spanOperation, + final Throwable failure, + final TagExtractor tagExtractor) { + + InstrumenterVertxTracer.super.receiveResponse(context, response, spanOperation, failure, tagExtractor); + } + + @Override + public Instrumenter getReceiveRequestInstrumenter() { + return null; + } + + @Override + public Instrumenter getSendResponseInstrumenter() { + return null; + } + + @Override + public Instrumenter getSendRequestInstrumenter() { + return redisClientInstrumenter; + } + + @Override + public Instrumenter getReceiveResponseInstrumenter() { + return redisClientInstrumenter; + } + + // From io.vertx.redis.client.impl.CommandReporter + static class CommandTrace { + private final Map attributes; + + CommandTrace(final Map attributes) { + this.attributes = attributes; + } + + static CommandTrace commandTrace(final Map attributes) { + return new CommandTrace(attributes); + } + + public String operation() { + return attributes.get("db.statement"); + } + + public String user() { + return attributes.get("db.user"); + } + + public String peerAddress() { + return attributes.get("peer.address"); + } + + public long dbIndex() { + return Long.parseLong(attributes.get("db.instance")); + } + } + + enum RedisClientAttributesGetter implements DbClientAttributesGetter { + INSTANCE; + + @Override + public String getStatement(final CommandTrace commandTrace) { + return null; + } + + @Override + public String getOperation(final CommandTrace commandTrace) { + return commandTrace.operation(); + } + + @Override + public String getSystem(final CommandTrace commandTrace) { + return SemanticAttributes.DbSystemValues.REDIS; + } + + @Override + public String getUser(final CommandTrace commandTrace) { + return commandTrace.user(); + } + + @Override + public String getName(final CommandTrace commandTrace) { + return null; + } + + @Override + public String getConnectionString(final CommandTrace commandTrace) { + return commandTrace.peerAddress(); + } + } + + enum RedisClientAttributesExtractor implements AttributesExtractor { + INSTANCE; + + @Override + public void onStart(AttributesBuilder attributes, io.opentelemetry.context.Context parentContext, + CommandTrace request) { + AttributesExtractorUtil.internalSet(attributes, SemanticAttributes.DB_REDIS_DATABASE_INDEX, request.dbIndex()); + } + + @Override + public void onEnd(AttributesBuilder attributes, + io.opentelemetry.context.Context context, + CommandTrace request, + Object response, + Throwable error) { + } + } +} diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/SqlClientInstrumenterVertxTracer.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/SqlClientInstrumenterVertxTracer.java index f5fc8922af2c9..b8bfdda2a408a 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/SqlClientInstrumenterVertxTracer.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/SqlClientInstrumenterVertxTracer.java @@ -38,7 +38,7 @@ public boolean canHandle(final R request, final TagExtractor tagExtractor return true; } - return tagExtractor.extract(request).containsKey("db.statement"); + return "sql".equals(tagExtractor.extract(request).get("db.type")); } @Override @@ -87,7 +87,7 @@ public Instrumenter getReceiveResponseInstrumenter() { return sqlClientInstrumenter; } - // From io.vertx.sqlclient.impl.tracing.QueryTracer + // From io.vertx.sqlclient.impl.tracing.QueryReporter static class QueryTrace { private final Map attributes; diff --git a/integration-tests/opentelemetry-redis-instrumentation/README.md b/integration-tests/opentelemetry-redis-instrumentation/README.md new file mode 100644 index 0000000000000..c39c7c5638a72 --- /dev/null +++ b/integration-tests/opentelemetry-redis-instrumentation/README.md @@ -0,0 +1,37 @@ +# OpenTelemetry Redis Instrumentation example + +## Running the tests + +By default, the tests of this module are disabled. To activate the test, use the `-Dtest-containers` option. + +NB: Tests in this module will attempt a connection to a local Redis listening on the default port. +If you have specific requirements, you can define a specific connection URL with `-Dquarkus.redis.hosts=host:port`. +Or, you can use the `-Dstart-containers` option to start the Redis Server container automatically. + +### Running tests in JVM mode + +To run, you can run the following command: + +``` +mvn clean install -Dtest-containers +``` + +Alternatively, to run the tests in JVM mode with Redis Server started as a Docker container, you can run the following command: + +``` +mvn clean install -Dtest-containers -Dstart-containers +``` + +### Running tests in native mode + +Additionally, you can generate a native image and run the tests for this native image by adding `-Dnative`: + +``` +mvn clean install -Dtest-containers -Dnative +``` + +You can also use the `-Dstart-containers` system property (as shown below), if you want the Redis Server container to be started automatically. + +``` +mvn clean install -Dtest-containers -Dnative -Dstart-containers +``` diff --git a/integration-tests/opentelemetry-redis-instrumentation/pom.xml b/integration-tests/opentelemetry-redis-instrumentation/pom.xml new file mode 100644 index 0000000000000..7f77e9357f5f6 --- /dev/null +++ b/integration-tests/opentelemetry-redis-instrumentation/pom.xml @@ -0,0 +1,237 @@ + + + 4.0.0 + + + io.quarkus + quarkus-integration-tests-parent + 999-SNAPSHOT + + + quarkus-integration-test-opentelemetry-redis-instrumentation + Quarkus - Integration Tests - OpenTelemetry Redis instrumentation + + + + io.quarkus + quarkus-opentelemetry + + + + + io.quarkus + quarkus-rest-jackson + + + + + io.opentelemetry + opentelemetry-sdk-testing + + + + io.quarkus + quarkus-redis-client + + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + org.awaitility + awaitility + test + + + + + io.quarkus + quarkus-rest-jackson-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-opentelemetry-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-redis-client-deployment + ${project.version} + pom + test + + + * + * + + + + + + + + + src/main/resources + true + + + + + maven-surefire-plugin + + true + + + + maven-failsafe-plugin + + true + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + + + test-redis + + + test-containers + + + + + + maven-surefire-plugin + + false + + + + maven-failsafe-plugin + + false + + + + + + + docker-redis + + + start-containers + + + + + + io.fabric8 + docker-maven-plugin + + + + redis:5.0.8-alpine + quarkus-test-redis + + + 6379:6379 + + + Redis: + default + cyan + + + + + + + + redis-cli PING + + + + + + + true + + + + docker-start + compile + + stop + start + + + + docker-stop + post-integration-test + + stop + + + + + + org.codehaus.mojo + exec-maven-plugin + + + docker-prune + generate-resources + + exec + + + ${docker-prune.location} + + + + + + + + + diff --git a/integration-tests/opentelemetry-redis-instrumentation/src/main/java/io/quarkus/io/opentelemetry/ExporterResource.java b/integration-tests/opentelemetry-redis-instrumentation/src/main/java/io/quarkus/io/opentelemetry/ExporterResource.java new file mode 100644 index 0000000000000..dad9f1b70f8dc --- /dev/null +++ b/integration-tests/opentelemetry-redis-instrumentation/src/main/java/io/quarkus/io/opentelemetry/ExporterResource.java @@ -0,0 +1,46 @@ +package io.quarkus.io.opentelemetry; + +import java.util.List; +import java.util.stream.Collectors; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; + +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.data.SpanData; + +@Path("/opentelemetry") +public class ExporterResource { + @Inject + InMemorySpanExporter inMemorySpanExporter; + + @GET + @Path("/reset") + public Response reset() { + inMemorySpanExporter.reset(); + return Response.ok().build(); + } + + @GET + @Path("/export") + public List export() { + return inMemorySpanExporter.getFinishedSpanItems() + .stream() + .filter(sd -> !sd.getName().contains("export") && !sd.getName().contains("reset")) + .collect(Collectors.toList()); + } + + @ApplicationScoped + static class InMemorySpanExporterProducer { + @Produces + @Singleton + InMemorySpanExporter inMemorySpanExporter() { + return InMemorySpanExporter.create(); + } + } +} diff --git a/integration-tests/opentelemetry-redis-instrumentation/src/main/java/io/quarkus/io/opentelemetry/RedisResource.java b/integration-tests/opentelemetry-redis-instrumentation/src/main/java/io/quarkus/io/opentelemetry/RedisResource.java new file mode 100644 index 0000000000000..e7757bdaf55ce --- /dev/null +++ b/integration-tests/opentelemetry-redis-instrumentation/src/main/java/io/quarkus/io/opentelemetry/RedisResource.java @@ -0,0 +1,54 @@ +package io.quarkus.io.opentelemetry; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + +import io.quarkus.redis.datasource.ReactiveRedisDataSource; +import io.quarkus.redis.datasource.RedisDataSource; +import io.quarkus.redis.datasource.value.ReactiveValueCommands; +import io.quarkus.redis.datasource.value.ValueCommands; +import io.smallrye.mutiny.Uni; + +@Path("/redis") +public class RedisResource { + + private final ValueCommands blocking; + private final ReactiveValueCommands reactive; + + @Inject + public RedisResource(RedisDataSource ds, + ReactiveRedisDataSource reactiveDs) { + blocking = ds.value(String.class); + reactive = reactiveDs.value(String.class); + } + + // synchronous + @GET + @Path("/sync/{key}") + public String getSync(@PathParam("key") String key) { + return blocking.get(key); + } + + @POST + @Path("/sync/{key}") + public void setSync(@PathParam("key") String key, String value) { + blocking.set(key, value); + } + + // reactive + @GET + @Path("/reactive/{key}") + public Uni getReactive(@PathParam("key") String key) { + return reactive.get(key); + } + + @POST + @Path("/reactive/{key}") + public Uni setReactive(@PathParam("key") String key, String value) { + return this.reactive.set(key, value); + } + +} diff --git a/integration-tests/opentelemetry-redis-instrumentation/src/main/resources/application.properties b/integration-tests/opentelemetry-redis-instrumentation/src/main/resources/application.properties new file mode 100644 index 0000000000000..4393ac06ad61e --- /dev/null +++ b/integration-tests/opentelemetry-redis-instrumentation/src/main/resources/application.properties @@ -0,0 +1,13 @@ +# Setting these for tests explicitly. Not required in normal application +quarkus.application.name=opentelemetry-redis-instrumentation-it +quarkus.application.version=999-SNAPSHOT + +# disable Dev Services +quarkus.devservices.enabled=false + +# set Redis Hosts +quarkus.redis.hosts=redis://localhost:6379/0 + +# speed up build +quarkus.otel.bsp.schedule.delay=100 +quarkus.otel.bsp.export.timeout=5s diff --git a/integration-tests/opentelemetry-redis-instrumentation/src/test/java/io/quarkus/it/opentelemetry/QuarkusRedisIT.java b/integration-tests/opentelemetry-redis-instrumentation/src/test/java/io/quarkus/it/opentelemetry/QuarkusRedisIT.java new file mode 100644 index 0000000000000..6b56ac5502755 --- /dev/null +++ b/integration-tests/opentelemetry-redis-instrumentation/src/test/java/io/quarkus/it/opentelemetry/QuarkusRedisIT.java @@ -0,0 +1,12 @@ +package io.quarkus.it.opentelemetry; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +class QuarkusRedisIT extends QuarkusRedisTest { + + @Override + String getKey(String k) { + return "native-" + k; + } +} diff --git a/integration-tests/opentelemetry-redis-instrumentation/src/test/java/io/quarkus/it/opentelemetry/QuarkusRedisTest.java b/integration-tests/opentelemetry-redis-instrumentation/src/test/java/io/quarkus/it/opentelemetry/QuarkusRedisTest.java new file mode 100644 index 0000000000000..b4485f22e04e5 --- /dev/null +++ b/integration-tests/opentelemetry-redis-instrumentation/src/test/java/io/quarkus/it/opentelemetry/QuarkusRedisTest.java @@ -0,0 +1,126 @@ +package io.quarkus.it.opentelemetry; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Duration; +import java.util.List; +import java.util.Map; + +import org.awaitility.Awaitility; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import io.restassured.common.mapper.TypeRef; + +@QuarkusTest +class QuarkusRedisTest { + static final String SYNC_KEY = "sync-key"; + static final String SYNC_VALUE = "sync-value"; + + static final String REACTIVE_KEY = "reactive-key"; + static final String REACTIVE_VALUE = "reactive-value"; + + static final String SET_OPERATION = "set"; + static final String GET_OPERATION = "get"; + + String getKey(String k) { + return k; + } + + @BeforeEach + void reset() { + given().get("/opentelemetry/reset").then().statusCode(HTTP_OK); + await().atMost(30, SECONDS).until(() -> { + // make sure spans are cleared + List> spans = getSpans(); + if (!spans.isEmpty()) { + given().get("/opentelemetry/reset").then().statusCode(HTTP_OK); + } + return spans.isEmpty(); + }); + } + + @Test + public void sync() { + String path = String.format("redis/sync/%s", getKey(SYNC_KEY)); + + RestAssured.given() + .body(SYNC_VALUE) + .when() + .post(path) + .then() + .statusCode(204); + + testTraced(SET_OPERATION); + reset(); + + RestAssured.given() + .when() + .get(path) + .then() + .statusCode(200) + .body(CoreMatchers.is(SYNC_VALUE)); + + testTraced(GET_OPERATION); + } + + @Test + public void reactive() { + String path = String.format("redis/reactive/%s", getKey(REACTIVE_KEY)); + + RestAssured.given() + .body(REACTIVE_VALUE) + .when() + .post(path) + .then() + .statusCode(204); + + testTraced(SET_OPERATION); + reset(); + + RestAssured.given() + .when() + .get(path) + .then() + .statusCode(200) + .body(CoreMatchers.is(REACTIVE_VALUE)); + + testTraced(GET_OPERATION); + } + + protected void testTraced(String expectedDBOperation) { + Awaitility.await().atMost(Duration.ofSeconds(55)).untilAsserted(() -> { + List> spans = getSpans(); + assertFalse(spans.isEmpty()); + + // Assert operation has been traced + boolean hitOperation = false; + for (Map spanData : spans) { + if (spanData.get("attributes") instanceof Map) { + final Map attributes = (Map) spanData.get("attributes"); + var dbOperation = attributes.get("db.operation"); + var dbSystem = attributes.get("db.system"); + if (expectedDBOperation.equals(dbOperation) && "redis".equals(dbSystem)) { + hitOperation = true; + break; + } + } + } + assertTrue(hitOperation, String.format("Redis Operation %s was not traced.", expectedDBOperation)); + }); + } + + private List> getSpans() { + return get("/opentelemetry/export").body().as(new TypeRef<>() { + }); + } +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index bd23f41c363e2..9db81c251220a 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -356,6 +356,7 @@ opentelemetry-grpc opentelemetry-vertx-exporter opentelemetry-reactive-messaging + opentelemetry-redis-instrumentation logging-json jaxb jaxp