From 878b15c4236bc43e0cf3e78c4c80c8e6e3523172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Thu, 3 Nov 2022 15:36:54 +0100 Subject: [PATCH] OpenTelemetry JDBC instrumentation - register Oracle driver manually fixes: #28915 --- .../io/quarkus/deployment/Capability.java | 1 + extensions/jdbc/jdbc-oracle/runtime/pom.xml | 5 + .../deployment/OpenTelemetryProcessor.java | 13 + .../runtime/OpenTelemetryRecorder.java | 29 ++ .../README.md | 16 + .../pom.xml | 298 ++++++++++++++++++ .../it/opentelemetry/ExporterResource.java | 46 +++ .../it/opentelemetry/PingPongResource.java | 50 +++ .../quarkus/it/opentelemetry/model/Hit.java | 15 + .../model/mariadb/MariaDbHit.java | 36 +++ .../opentelemetry/model/oracle/OracleHit.java | 36 +++ .../it/opentelemetry/model/pg/PgHit.java | 36 +++ .../resources/META-INF/resources/test.html | 1 + .../src/main/resources/application.properties | 31 ++ .../MariaDbLifecycleManager.java | 52 +++ ...aDbOpenTelemetryJdbcInstrumentationIT.java | 8 + ...bOpenTelemetryJdbcInstrumentationTest.java | 17 + .../OpenTelemetryJdbcInstrumentationTest.java | 55 ++++ .../opentelemetry/OracleLifecycleManager.java | 44 +++ ...cleOpenTelemetryJdbcInstrumentationIT.java | 8 + ...eOpenTelemetryJdbcInstrumentationTest.java | 17 + .../PostgreSqlLifecycleManager.java | 52 +++ ...resOpenTelemetryJdbcInstrumentationIT.java | 8 + ...sOpenTelemetryJdbcInstrumentationTest.java | 17 + integration-tests/pom.xml | 1 + 25 files changed, 892 insertions(+) create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/README.md create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/pom.xml create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/ExporterResource.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/PingPongResource.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/Hit.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/mariadb/MariaDbHit.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/oracle/OracleHit.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/pg/PgHit.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/META-INF/resources/test.html create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/application.properties create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbLifecycleManager.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationIT.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationTest.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryJdbcInstrumentationTest.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleLifecycleManager.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationIT.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationTest.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgreSqlLifecycleManager.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationIT.java create mode 100644 integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationTest.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/Capability.java b/core/deployment/src/main/java/io/quarkus/deployment/Capability.java index 29d12c53be6e1..8fa0a4f0fcd36 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/Capability.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/Capability.java @@ -134,4 +134,5 @@ public interface Capability { String KAFKA = QUARKUS_PREFIX + "kafka"; String SMALLRYE_REACTIVE_MESSAGING = QUARKUS_PREFIX + "smallrye.reactive.messaging"; + String JDBC_ORACLE = QUARKUS_PREFIX + "jdbc.oracle"; } diff --git a/extensions/jdbc/jdbc-oracle/runtime/pom.xml b/extensions/jdbc/jdbc-oracle/runtime/pom.xml index 52e99e443461e..0e692fb507e75 100644 --- a/extensions/jdbc/jdbc-oracle/runtime/pom.xml +++ b/extensions/jdbc/jdbc-oracle/runtime/pom.xml @@ -43,6 +43,11 @@ io.quarkus quarkus-extension-maven-plugin + + + io.quarkus.jdbc.oracle + + maven-compiler-plugin 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 f22257e9c1d7b..d95deaa56377e 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 @@ -173,4 +173,17 @@ void createOpenTelemetry( void storeVertxOnContextStorage(OpenTelemetryRecorder recorder, CoreVertxBuildItem vertx) { recorder.storeVertxOnContextStorage(vertx.getVertx()); } + + /** + * 'OracleDriver' register itself as driver in static initialization block, however we don't want to + * force runtime initialization for compatibility reasons, for more information please check: + * io.quarkus.jdbc.oracle.deployment.OracleMetadataOverrides#runtimeInitializeDriver + */ + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void registerOracleDriver(Capabilities capabilities, OpenTelemetryRecorder recorder) { + if (capabilities.isPresent(Capability.JDBC_ORACLE)) { + recorder.registerOracleDriver(); + } + } } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java index a6a4c760feb48..97291c9268581 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java @@ -1,7 +1,13 @@ package io.quarkus.opentelemetry.runtime; +import java.lang.reflect.InvocationTargetException; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; import java.util.function.Supplier; +import org.jboss.logging.Logger; + import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.context.ContextStorage; @@ -16,6 +22,8 @@ @Recorder public class OpenTelemetryRecorder { + private static final Logger LOG = Logger.getLogger(OpenTelemetryRecorder.class); + /* STATIC INIT */ public void resetGlobalOpenTelemetryForDevMode() { GlobalOpenTelemetry.resetForTest(); @@ -46,4 +54,25 @@ public void eagerlyCreateContextStorage() { public void storeVertxOnContextStorage(Supplier vertx) { QuarkusContextStorage.vertx = vertx.get(); } + + public void registerOracleDriver() { + try { + var constructors = Class + .forName("oracle.jdbc.driver.OracleDriver", true, Thread.currentThread().getContextClassLoader()) + .getConstructors(); + if (constructors.length == 1) { + // register OracleDriver + DriverManager.registerDriver((Driver) constructors[0].newInstance()); + } else { + // we need default constructor, ATM there is just one + LOG.warn( + "Class 'oracle.jdbc.driver.OracleDriver' has more than one constructor and won't be registered as driver." + + + " JDBC instrumentation might not work properly in native mode."); + } + } catch (SQLException | InvocationTargetException | InstantiationException | IllegalAccessException + | ClassNotFoundException e) { + LOG.warn("Failed to register Oracle driver. JDBC instrumentation might not work properly in native mode."); + } + } } diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/README.md b/integration-tests/opentelemetry-jdbc-instrumentation/README.md new file mode 100644 index 0000000000000..2d309b64858d8 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/README.md @@ -0,0 +1,16 @@ +# OpenTelemetry JDBC instrumentation example + +## Running the tests + + +To run the tests in a standard JVM with an Oracle database started as a Docker container, you can run the following command: + +``` +mvn verify -Dtest-containers +``` + +To also test as a native image, add `-Dnative`: + +``` +mvn verify -Dtest-containers -Dnative +``` diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/pom.xml b/integration-tests/opentelemetry-jdbc-instrumentation/pom.xml new file mode 100644 index 0000000000000..54904874158df --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/pom.xml @@ -0,0 +1,298 @@ + + + 4.0.0 + + + io.quarkus + quarkus-integration-tests-parent + 999-SNAPSHOT + + + quarkus-integration-test-opentelemetry-jdbc-instrumentation + Quarkus - Integration Tests - OpenTelemetry JDBC instrumentation + + + + io.quarkus + quarkus-opentelemetry + + + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + + + io.opentelemetry + opentelemetry-sdk-testing + + + + + io.opentelemetry.instrumentation + opentelemetry-jdbc + + + io.quarkus + quarkus-jdbc-oracle + + + io.quarkus + quarkus-jdbc-postgresql + + + io.quarkus + quarkus-jdbc-mariadb + + + io.quarkus + quarkus-hibernate-orm-panache + + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + org.awaitility + awaitility + test + + + org.testcontainers + testcontainers + test + + + org.testcontainers + oracle-xe + test + + + junit + junit + + + + + org.testcontainers + postgresql + + + junit + junit + + + + + org.testcontainers + mariadb + + + junit + junit + + + + + + + io.quarkus + quarkus-resteasy-reactive-jackson-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-opentelemetry-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-hibernate-orm-panache-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-jdbc-oracle-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-jdbc-mariadb-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-jdbc-postgresql-deployment + ${project.version} + pom + test + + + * + * + + + + + + + + + + maven-surefire-plugin + + true + + + + maven-failsafe-plugin + + true + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + + + native-image + + + native + + + + + native + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${native.surefire.skip} + + + + + maven-failsafe-plugin + + + + integration-test + verify + + + + + ${project.build.directory}/${project.build.finalName}-runner + + + + + + + + + + + test-jdbc-instrumentation + + + test-containers + + + + + + maven-surefire-plugin + + false + + ${oracle.image} + ${postgres.image} + ${mariadb.image} + + + + + maven-failsafe-plugin + + false + + ${oracle.image} + ${postgres.image} + ${mariadb.image} + + + + + + + + diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/ExporterResource.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/ExporterResource.java new file mode 100644 index 0000000000000..144bcc4911d8a --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/ExporterResource.java @@ -0,0 +1,46 @@ +package io.quarkus.it.opentelemetry; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.data.SpanData; + +@Path("") +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-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/PingPongResource.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/PingPongResource.java new file mode 100644 index 0000000000000..e37621340bd4f --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/PingPongResource.java @@ -0,0 +1,50 @@ +package io.quarkus.it.opentelemetry; + +import java.util.function.Supplier; + +import javax.enterprise.context.ApplicationScoped; +import javax.transaction.Transactional; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import io.quarkus.it.opentelemetry.model.Hit; +import io.quarkus.it.opentelemetry.model.mariadb.MariaDbHit; +import io.quarkus.it.opentelemetry.model.oracle.OracleHit; +import io.quarkus.it.opentelemetry.model.pg.PgHit; + +@ApplicationScoped +@Path("/") +public class PingPongResource { + + @Transactional + @POST + @Produces(MediaType.APPLICATION_JSON) + @Path("/hit/{tenant}") + public Hit createHit(@QueryParam("id") Long id, @PathParam("tenant") String tenant) { + switch (tenant) { + case "postgresql": + persist(PgHit::new, id); + return PgHit.findById(id); + case "oracle": + persist(OracleHit::new, id); + return OracleHit.findById(id); + case "mariadb": + persist(MariaDbHit::new, id); + return MariaDbHit.findById(id); + default: + throw new IllegalArgumentException(); + } + } + + private void persist(Supplier hitSupplier, Long id) { + Hit hit = hitSupplier.get(); + hit.setId(id); + hit.setMessage("Hit message."); + hit.persist(); + } + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/Hit.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/Hit.java new file mode 100644 index 0000000000000..518360e01e370 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/Hit.java @@ -0,0 +1,15 @@ +package io.quarkus.it.opentelemetry.model; + +public interface Hit { + + Long getId(); + + String getMessage(); + + void setId(Long id); + + void setMessage(String message); + + void persist(); + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/mariadb/MariaDbHit.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/mariadb/MariaDbHit.java new file mode 100644 index 0000000000000..c3d77e52cc23b --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/mariadb/MariaDbHit.java @@ -0,0 +1,36 @@ +package io.quarkus.it.opentelemetry.model.mariadb; + +import javax.persistence.Entity; +import javax.persistence.Id; + +import io.quarkus.hibernate.orm.panache.PanacheEntityBase; +import io.quarkus.it.opentelemetry.model.Hit; + +@Entity +public class MariaDbHit extends PanacheEntityBase implements Hit { + + @Id + public Long id; + + public String message; + + @Override + public Long getId() { + return id; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public void setId(Long id) { + this.id = id; + } + + @Override + public void setMessage(String message) { + this.message = message; + } +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/oracle/OracleHit.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/oracle/OracleHit.java new file mode 100644 index 0000000000000..490c7fa5cf521 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/oracle/OracleHit.java @@ -0,0 +1,36 @@ +package io.quarkus.it.opentelemetry.model.oracle; + +import javax.persistence.Entity; +import javax.persistence.Id; + +import io.quarkus.hibernate.orm.panache.PanacheEntityBase; +import io.quarkus.it.opentelemetry.model.Hit; + +@Entity +public class OracleHit extends PanacheEntityBase implements Hit { + + @Id + public Long id; + + public String message; + + @Override + public Long getId() { + return id; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public void setId(Long id) { + this.id = id; + } + + @Override + public void setMessage(String message) { + this.message = message; + } +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/pg/PgHit.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/pg/PgHit.java new file mode 100644 index 0000000000000..a79d1b79c7c4a --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/java/io/quarkus/it/opentelemetry/model/pg/PgHit.java @@ -0,0 +1,36 @@ +package io.quarkus.it.opentelemetry.model.pg; + +import javax.persistence.Entity; +import javax.persistence.Id; + +import io.quarkus.hibernate.orm.panache.PanacheEntityBase; +import io.quarkus.it.opentelemetry.model.Hit; + +@Entity +public class PgHit extends PanacheEntityBase implements Hit { + + @Id + public Long id; + + public String message; + + @Override + public Long getId() { + return id; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public void setId(Long id) { + this.id = id; + } + + @Override + public void setMessage(String message) { + this.message = message; + } +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/META-INF/resources/test.html b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/META-INF/resources/test.html new file mode 100644 index 0000000000000..d3e7968fdf060 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/META-INF/resources/test.html @@ -0,0 +1 @@ +Test diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/application.properties b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/application.properties new file mode 100644 index 0000000000000..9c96d8df2afc2 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/main/resources/application.properties @@ -0,0 +1,31 @@ +# Setting these for tests explicitly. Not required in normal application +quarkus.application.name=opentelemetry-jdbc-instrumentation-it +quarkus.application.version=999-SNAPSHOT + +# JDBC instrumentation setting +driver=io.opentelemetry.instrumentation.jdbc.OpenTelemetryDriver +model-base-dir=io.quarkus.it.opentelemetry.model. + +# Oracle data source +quarkus.hibernate-orm.oracle.datasource=oracle +quarkus.hibernate-orm.oracle.packages=${model-base-dir}oracle +quarkus.hibernate-orm.oracle.database.generation=none +quarkus.datasource.oracle.db-kind=oracle +quarkus.datasource.oracle.jdbc.driver=${driver} +quarkus.datasource.oracle.jdbc.max-size=1 + +# MariaDB data source +quarkus.hibernate-orm.mariadb.datasource=mariadb +quarkus.hibernate-orm.mariadb.packages=${model-base-dir}mariadb +quarkus.hibernate-orm.mariadb.database.generation=none +quarkus.datasource.mariadb.db-kind=mariadb +quarkus.datasource.mariadb.jdbc.driver=${driver} +quarkus.datasource.mariadb.jdbc.max-size=1 + +# PostgreSQL data source +quarkus.hibernate-orm.postgresql.datasource=postgresql +quarkus.hibernate-orm.postgresql.packages=${model-base-dir}pg +quarkus.hibernate-orm.postgresql.database.generation=none +quarkus.datasource.postgresql.db-kind=postgresql +quarkus.datasource.postgresql.jdbc.driver=${driver} +quarkus.datasource.postgresql.jdbc.max-size=1 diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbLifecycleManager.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbLifecycleManager.java new file mode 100644 index 0000000000000..3757b7da7ea95 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbLifecycleManager.java @@ -0,0 +1,52 @@ +package io.quarkus.it.opentelemetry; + +import java.util.HashMap; +import java.util.Map; + +import org.jboss.logging.Logger; +import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.utility.DockerImageName; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; + +public class MariaDbLifecycleManager implements QuarkusTestResourceLifecycleManager { + private static final Logger LOGGER = Logger.getLogger(MariaDbLifecycleManager.class); + private static final String QUARKUS = "quarkus"; + private static final String MARIADB_IMAGE = System.getProperty("mariadb.image"); + private StartedMariaDBContainer mariaDbContainer; + + @Override + public Map start() { + mariaDbContainer = new StartedMariaDBContainer(); + LOGGER.info(mariaDbContainer.getLogs()); + + Map properties = new HashMap<>(); + properties.put("quarkus.datasource.mariadb.jdbc.url", + String.format("jdbc:otel:mariadb://%s:%s/%s", mariaDbContainer.getHost(), + mariaDbContainer.getFirstMappedPort(), QUARKUS)); + properties.put("quarkus.datasource.mariadb.password", QUARKUS); + properties.put("quarkus.datasource.mariadb.username", QUARKUS); + properties.put("quarkus.hibernate-orm.mariadb.database.generation", "drop-and-create"); + + return properties; + } + + @Override + public void stop() { + mariaDbContainer.stop(); + } + + private static final class StartedMariaDBContainer extends MariaDBContainer { + + public StartedMariaDBContainer() { + super(DockerImageName + .parse(MARIADB_IMAGE) + .asCompatibleSubstituteFor(DockerImageName.parse(MariaDBContainer.NAME))); + withDatabaseName(QUARKUS); + withUsername(QUARKUS); + withPassword(QUARKUS); + addExposedPort(3306); + start(); + } + } +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationIT.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationIT.java new file mode 100644 index 0000000000000..618f3c9060955 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationIT.java @@ -0,0 +1,8 @@ +package io.quarkus.it.opentelemetry; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class MariaDbOpenTelemetryJdbcInstrumentationIT extends MariaDbOpenTelemetryJdbcInstrumentationTest { + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationTest.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationTest.java new file mode 100644 index 0000000000000..3aac150dd4311 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/MariaDbOpenTelemetryJdbcInstrumentationTest.java @@ -0,0 +1,17 @@ +package io.quarkus.it.opentelemetry; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@QuarkusTestResource(MariaDbLifecycleManager.class) +public class MariaDbOpenTelemetryJdbcInstrumentationTest extends OpenTelemetryJdbcInstrumentationTest { + + @Test + void testMariaDbQueryTraced() { + testQueryTraced("mariadb", "MariaDbHit"); + } + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryJdbcInstrumentationTest.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryJdbcInstrumentationTest.java new file mode 100644 index 0000000000000..37e4fccdbbef9 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryJdbcInstrumentationTest.java @@ -0,0 +1,55 @@ +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.assertTrue; + +import java.util.List; +import java.util.Map; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeEach; + +import io.restassured.common.mapper.TypeRef; + +public abstract class OpenTelemetryJdbcInstrumentationTest { + + @BeforeEach + void reset() { + given().get("/reset").then().statusCode(HTTP_OK); + await().atMost(5, SECONDS).until(() -> getSpans().size() == 0); + } + + private List> getSpans() { + return get("/export").body().as(new TypeRef<>() { + }); + } + + protected void testQueryTraced(String dbKind, String expectedTable) { + given() + .queryParam("id", 1) + .when().post("/hit/" + dbKind) + .then() + .statusCode(200) + .body("message", Matchers.equalTo("Hit message.")); + + // Assert insert has been traced + boolean hitInserted = false; + for (Map spanData : getSpans()) { + if (spanData.get("attributes") instanceof Map) { + final Map attributes = (Map) spanData.get("attributes"); + var dbOperation = attributes.get("db.operation"); + var dbTable = attributes.get("db.sql.table"); + if ("INSERT".equals(dbOperation) && expectedTable.equals(dbTable)) { + hitInserted = true; + break; + } + } + } + assertTrue(hitInserted, "JDBC insert statement was not traced."); + } + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleLifecycleManager.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleLifecycleManager.java new file mode 100644 index 0000000000000..18c6302133354 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleLifecycleManager.java @@ -0,0 +1,44 @@ +package io.quarkus.it.opentelemetry; + +import java.util.HashMap; +import java.util.Map; + +import org.jboss.logging.Logger; +import org.testcontainers.containers.OracleContainer; +import org.testcontainers.utility.DockerImageName; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; + +public class OracleLifecycleManager implements QuarkusTestResourceLifecycleManager { + private static final Logger LOGGER = Logger.getLogger(OracleLifecycleManager.class); + private OracleContainer oracle; + private static final String QUARKUS = "quarkus"; + private static final String ORACLE_IMAGE = System.getProperty("oracle.image"); + private static final String ORACLE_IMAGE_NAME = "gvenzl/oracle-xe"; + + @Override + public Map start() { + oracle = new OracleContainer(DockerImageName.parse(ORACLE_IMAGE).asCompatibleSubstituteFor(ORACLE_IMAGE_NAME)) + .withDatabaseName(QUARKUS) + .withPassword(QUARKUS) + .withUsername(QUARKUS) + .withExposedPorts(1521); + oracle.start(); + LOGGER.info(oracle.getLogs()); + + Map properties = new HashMap<>(); + properties.put("quarkus.datasource.\"oracle\".jdbc.url", + String.format("jdbc:otel:oracle:thin:@%s:%s/quarkus", oracle.getHost(), oracle.getOraclePort())); + properties.put("quarkus.datasource.\"oracle\".password", QUARKUS); + properties.put("quarkus.datasource.\"oracle\".username", "quarkus"); + properties.put("quarkus.hibernate-orm.\"oracle\".database.generation", "update"); + + return properties; + } + + @Override + public void stop() { + oracle.stop(); + } + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationIT.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationIT.java new file mode 100644 index 0000000000000..e7ccd488acefe --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationIT.java @@ -0,0 +1,8 @@ +package io.quarkus.it.opentelemetry; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class OracleOpenTelemetryJdbcInstrumentationIT extends OracleOpenTelemetryJdbcInstrumentationTest { + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationTest.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationTest.java new file mode 100644 index 0000000000000..5bc7f382014ef --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/OracleOpenTelemetryJdbcInstrumentationTest.java @@ -0,0 +1,17 @@ +package io.quarkus.it.opentelemetry; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@QuarkusTestResource(OracleLifecycleManager.class) +public class OracleOpenTelemetryJdbcInstrumentationTest extends OpenTelemetryJdbcInstrumentationTest { + + @Test + void testOracleQueryTraced() { + testQueryTraced("oracle", "OracleHit"); + } + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgreSqlLifecycleManager.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgreSqlLifecycleManager.java new file mode 100644 index 0000000000000..4ca795b967b65 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgreSqlLifecycleManager.java @@ -0,0 +1,52 @@ +package io.quarkus.it.opentelemetry; + +import java.util.HashMap; +import java.util.Map; + +import org.jboss.logging.Logger; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.utility.DockerImageName; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; + +public class PostgreSqlLifecycleManager implements QuarkusTestResourceLifecycleManager { + private static final Logger LOGGER = Logger.getLogger(PostgreSqlLifecycleManager.class); + private static final String QUARKUS = "quarkus"; + private static final String POSTGRES_IMAGE = System.getProperty("postgres.image"); + private StartedPostgresContainer postgresContainer; + + @Override + public Map start() { + postgresContainer = new StartedPostgresContainer(); + LOGGER.info(postgresContainer.getLogs()); + + Map properties = new HashMap<>(); + properties.put("quarkus.datasource.postgresql.jdbc.url", + String.format("jdbc:otel:postgresql://%s:%s/%s", postgresContainer.getHost(), + postgresContainer.getFirstMappedPort(), QUARKUS)); + properties.put("quarkus.datasource.postgresql.password", QUARKUS); + properties.put("quarkus.datasource.postgresql.username", QUARKUS); + properties.put("quarkus.hibernate-orm.postgresql.database.generation", "drop-and-create"); + + return properties; + } + + @Override + public void stop() { + postgresContainer.stop(); + } + + private static final class StartedPostgresContainer extends PostgreSQLContainer { + + public StartedPostgresContainer() { + super(DockerImageName + .parse(POSTGRES_IMAGE) + .asCompatibleSubstituteFor(DockerImageName.parse(PostgreSQLContainer.IMAGE))); + withDatabaseName(QUARKUS); + withUsername(QUARKUS); + withPassword(QUARKUS); + addExposedPort(5432); + start(); + } + } +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationIT.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationIT.java new file mode 100644 index 0000000000000..08e62277beea2 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationIT.java @@ -0,0 +1,8 @@ +package io.quarkus.it.opentelemetry; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class PostgresOpenTelemetryJdbcInstrumentationIT extends PostgresOpenTelemetryJdbcInstrumentationTest { + +} diff --git a/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationTest.java b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationTest.java new file mode 100644 index 0000000000000..9f60405f3e0d4 --- /dev/null +++ b/integration-tests/opentelemetry-jdbc-instrumentation/src/test/java/io/quarkus/it/opentelemetry/PostgresOpenTelemetryJdbcInstrumentationTest.java @@ -0,0 +1,17 @@ +package io.quarkus.it.opentelemetry; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@QuarkusTestResource(PostgreSqlLifecycleManager.class) +public class PostgresOpenTelemetryJdbcInstrumentationTest extends OpenTelemetryJdbcInstrumentationTest { + + @Test + void testPostgreSqlQueryTraced() { + testQueryTraced("postgresql", "PgHit"); + } + +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 559d728b5ef37..9a4c1656bfb58 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -310,6 +310,7 @@ micrometer-mp-metrics micrometer-prometheus opentelemetry + opentelemetry-jdbc-instrumentation opentelemetry-vertx opentelemetry-reactive opentelemetry-grpc