Add test for hibernate-reactive (#9225)
This commit is contained in:
parent
2f8db1b443
commit
42e2f738cc
|
@ -25,7 +25,7 @@ public class HibernateInstrumentationModule extends InstrumentationModule {
|
||||||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
||||||
return hasClassesNamed(
|
return hasClassesNamed(
|
||||||
// not present before 6.0
|
// not present before 6.0
|
||||||
"org.hibernate.query.Query");
|
"org.hibernate.query.spi.SqmQuery");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,10 +15,67 @@ dependencies {
|
||||||
library("io.vertx:vertx-sql-client:4.0.0")
|
library("io.vertx:vertx-sql-client:4.0.0")
|
||||||
compileOnly("io.vertx:vertx-codegen:4.0.0")
|
compileOnly("io.vertx:vertx-codegen:4.0.0")
|
||||||
|
|
||||||
|
// for hibernateReactive2Test
|
||||||
|
testInstrumentation(project(":instrumentation:hibernate:hibernate-6.0:javaagent"))
|
||||||
|
|
||||||
testLibrary("io.vertx:vertx-pg-client:4.0.0")
|
testLibrary("io.vertx:vertx-pg-client:4.0.0")
|
||||||
testLibrary("io.vertx:vertx-codegen:4.0.0")
|
testLibrary("io.vertx:vertx-codegen:4.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<Test>().configureEach {
|
val latestDepTest = findProperty("testLatestDeps") as Boolean
|
||||||
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
|
|
||||||
|
testing {
|
||||||
|
suites {
|
||||||
|
val hibernateReactive1Test by registering(JvmTestSuite::class) {
|
||||||
|
dependencies {
|
||||||
|
implementation("org.testcontainers:testcontainers")
|
||||||
|
if (latestDepTest) {
|
||||||
|
implementation("org.hibernate.reactive:hibernate-reactive-core:1.+")
|
||||||
|
implementation("io.vertx:vertx-pg-client:+")
|
||||||
|
} else {
|
||||||
|
implementation("org.hibernate.reactive:hibernate-reactive-core:1.0.0.Final")
|
||||||
|
implementation("io.vertx:vertx-pg-client:4.1.5")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hibernateReactive2Test by registering(JvmTestSuite::class) {
|
||||||
|
dependencies {
|
||||||
|
implementation("org.testcontainers:testcontainers")
|
||||||
|
if (latestDepTest) {
|
||||||
|
implementation("org.hibernate.reactive:hibernate-reactive-core:2.+")
|
||||||
|
implementation("io.vertx:vertx-pg-client:+")
|
||||||
|
} else {
|
||||||
|
implementation("org.hibernate.reactive:hibernate-reactive-core:2.0.0.Final")
|
||||||
|
implementation("io.vertx:vertx-pg-client:4.4.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
withType<Test>().configureEach {
|
||||||
|
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
|
||||||
|
}
|
||||||
|
named("compileHibernateReactive2TestJava", JavaCompile::class).configure {
|
||||||
|
options.release.set(11)
|
||||||
|
}
|
||||||
|
val testJavaVersion =
|
||||||
|
gradle.startParameter.projectProperties.get("testJavaVersion")?.let(JavaVersion::toVersion)
|
||||||
|
?: JavaVersion.current()
|
||||||
|
if (testJavaVersion.isJava8) {
|
||||||
|
named("hibernateReactive2Test", Test::class).configure {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
if (latestDepTest) {
|
||||||
|
named("hibernateReactive1Test", Test::class).configure {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check {
|
||||||
|
dependsOn(testing.suites)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v1_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_NAME;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_OPERATION;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_SQL_TABLE;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_STATEMENT;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_USER;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_NAME;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_PORT;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
import javax.persistence.Persistence;
|
||||||
|
import org.hibernate.reactive.mutiny.Mutiny;
|
||||||
|
import org.hibernate.reactive.stage.Stage;
|
||||||
|
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;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||||
|
|
||||||
|
class HibernateReactiveTest {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(HibernateReactiveTest.class);
|
||||||
|
|
||||||
|
private static final String USER_DB = "SA";
|
||||||
|
private static final String PW_DB = "password123";
|
||||||
|
private static final String DB = "tempdb";
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
private static GenericContainer<?> container;
|
||||||
|
private static int port;
|
||||||
|
private static EntityManagerFactory entityManagerFactory;
|
||||||
|
private static Mutiny.SessionFactory mutinySessionFactory;
|
||||||
|
private static Stage.SessionFactory stageSessionFactory;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setUp() {
|
||||||
|
container =
|
||||||
|
new GenericContainer<>("postgres:9.6.8")
|
||||||
|
.withEnv("POSTGRES_USER", USER_DB)
|
||||||
|
.withEnv("POSTGRES_PASSWORD", PW_DB)
|
||||||
|
.withEnv("POSTGRES_DB", DB)
|
||||||
|
.withExposedPorts(5432)
|
||||||
|
.withLogConsumer(new Slf4jLogConsumer(logger))
|
||||||
|
.withStartupTimeout(Duration.ofMinutes(2));
|
||||||
|
container.start();
|
||||||
|
|
||||||
|
port = container.getMappedPort(5432);
|
||||||
|
System.setProperty("db.port", String.valueOf(port));
|
||||||
|
|
||||||
|
entityManagerFactory = Persistence.createEntityManagerFactory("test-pu");
|
||||||
|
|
||||||
|
Value value = new Value("name");
|
||||||
|
value.setId(1L);
|
||||||
|
|
||||||
|
mutinySessionFactory = entityManagerFactory.unwrap(Mutiny.SessionFactory.class);
|
||||||
|
stageSessionFactory = entityManagerFactory.unwrap(Stage.SessionFactory.class);
|
||||||
|
|
||||||
|
mutinySessionFactory
|
||||||
|
.withTransaction((session, tx) -> session.merge(value))
|
||||||
|
.await()
|
||||||
|
.atMost(Duration.ofSeconds(30));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void cleanUp() {
|
||||||
|
if (entityManagerFactory != null) {
|
||||||
|
entityManagerFactory.close();
|
||||||
|
}
|
||||||
|
if (mutinySessionFactory != null) {
|
||||||
|
mutinySessionFactory.close();
|
||||||
|
}
|
||||||
|
if (stageSessionFactory != null) {
|
||||||
|
stageSessionFactory.close();
|
||||||
|
}
|
||||||
|
container.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMutiny() {
|
||||||
|
testing.runWithSpan(
|
||||||
|
"parent",
|
||||||
|
() -> {
|
||||||
|
mutinySessionFactory
|
||||||
|
.withSession(
|
||||||
|
session ->
|
||||||
|
session
|
||||||
|
.find(Value.class, 1L)
|
||||||
|
.invoke(
|
||||||
|
value -> {
|
||||||
|
testing.runWithSpan("callback", () -> {});
|
||||||
|
}))
|
||||||
|
.await()
|
||||||
|
.atMost(Duration.ofSeconds(30));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testStage() throws Exception {
|
||||||
|
testing
|
||||||
|
.runWithSpan(
|
||||||
|
"parent",
|
||||||
|
() ->
|
||||||
|
stageSessionFactory
|
||||||
|
.withSession(
|
||||||
|
session ->
|
||||||
|
session
|
||||||
|
.find(Value.class, 1L)
|
||||||
|
.thenAccept(
|
||||||
|
value -> {
|
||||||
|
testing.runWithSpan("callback", () -> {});
|
||||||
|
}))
|
||||||
|
.toCompletableFuture())
|
||||||
|
.get(30, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
assertTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertTrace() {
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL),
|
||||||
|
span ->
|
||||||
|
span.hasName("SELECT tempdb.Value")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasParent(trace.getSpan(0))
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(DB_NAME, DB),
|
||||||
|
equalTo(DB_USER, USER_DB),
|
||||||
|
equalTo(
|
||||||
|
DB_STATEMENT,
|
||||||
|
"select value0_.id as id1_0_0_, value0_.name as name2_0_0_ from Value value0_ where value0_.id=$?"),
|
||||||
|
equalTo(DB_OPERATION, "SELECT"),
|
||||||
|
equalTo(DB_SQL_TABLE, "Value"),
|
||||||
|
equalTo(NET_PEER_NAME, "localhost"),
|
||||||
|
equalTo(NET_PEER_PORT, port)),
|
||||||
|
span ->
|
||||||
|
span.hasName("callback")
|
||||||
|
.hasKind(SpanKind.INTERNAL)
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v1_0;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table
|
||||||
|
public class Value {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Value() {}
|
||||||
|
|
||||||
|
public Value(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String title) {
|
||||||
|
name = title;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||||
|
version="2.0">
|
||||||
|
|
||||||
|
<persistence-unit name="test-pu">
|
||||||
|
<provider>org.hibernate.reactive.provider.ReactivePersistenceProvider</provider>
|
||||||
|
<class>io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v1_0.Value</class>
|
||||||
|
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
|
||||||
|
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://localhost:${db.port}/tempdb"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.user" value="SA"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.password" value="password123"/>
|
||||||
|
<property name="hibernate.connection.pool_size" value="10"/>
|
||||||
|
<property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/>
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
</persistence>
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v2_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_NAME;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_OPERATION;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_SQL_TABLE;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_STATEMENT;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.DB_USER;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_NAME;
|
||||||
|
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_PORT;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
|
import jakarta.persistence.Persistence;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.hibernate.reactive.mutiny.Mutiny;
|
||||||
|
import org.hibernate.reactive.stage.Stage;
|
||||||
|
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;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||||
|
|
||||||
|
class HibernateReactiveTest {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(HibernateReactiveTest.class);
|
||||||
|
|
||||||
|
private static final String USER_DB = "SA";
|
||||||
|
private static final String PW_DB = "password123";
|
||||||
|
private static final String DB = "tempdb";
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
private static GenericContainer<?> container;
|
||||||
|
private static int port;
|
||||||
|
private static EntityManagerFactory entityManagerFactory;
|
||||||
|
private static Mutiny.SessionFactory mutinySessionFactory;
|
||||||
|
private static Stage.SessionFactory stageSessionFactory;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setUp() {
|
||||||
|
container =
|
||||||
|
new GenericContainer<>("postgres:9.6.8")
|
||||||
|
.withEnv("POSTGRES_USER", USER_DB)
|
||||||
|
.withEnv("POSTGRES_PASSWORD", PW_DB)
|
||||||
|
.withEnv("POSTGRES_DB", DB)
|
||||||
|
.withExposedPorts(5432)
|
||||||
|
.withLogConsumer(new Slf4jLogConsumer(logger))
|
||||||
|
.withStartupTimeout(Duration.ofMinutes(2));
|
||||||
|
container.start();
|
||||||
|
|
||||||
|
port = container.getMappedPort(5432);
|
||||||
|
System.setProperty("db.port", String.valueOf(port));
|
||||||
|
|
||||||
|
entityManagerFactory = Persistence.createEntityManagerFactory("test-pu");
|
||||||
|
|
||||||
|
Value value = new Value("name");
|
||||||
|
value.setId(1L);
|
||||||
|
|
||||||
|
mutinySessionFactory = entityManagerFactory.unwrap(Mutiny.SessionFactory.class);
|
||||||
|
stageSessionFactory = entityManagerFactory.unwrap(Stage.SessionFactory.class);
|
||||||
|
|
||||||
|
mutinySessionFactory
|
||||||
|
.withTransaction((session, tx) -> session.merge(value))
|
||||||
|
.await()
|
||||||
|
.atMost(Duration.ofSeconds(30));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void cleanUp() {
|
||||||
|
if (entityManagerFactory != null) {
|
||||||
|
entityManagerFactory.close();
|
||||||
|
}
|
||||||
|
if (mutinySessionFactory != null) {
|
||||||
|
mutinySessionFactory.close();
|
||||||
|
}
|
||||||
|
if (stageSessionFactory != null) {
|
||||||
|
stageSessionFactory.close();
|
||||||
|
}
|
||||||
|
container.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMutiny() {
|
||||||
|
testing.runWithSpan(
|
||||||
|
"parent",
|
||||||
|
() -> {
|
||||||
|
mutinySessionFactory
|
||||||
|
.withSession(
|
||||||
|
session ->
|
||||||
|
session
|
||||||
|
.find(Value.class, 1L)
|
||||||
|
.invoke(
|
||||||
|
value -> {
|
||||||
|
testing.runWithSpan("callback", () -> {});
|
||||||
|
}))
|
||||||
|
.await()
|
||||||
|
.atMost(Duration.ofSeconds(30));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testStage() throws Exception {
|
||||||
|
testing
|
||||||
|
.runWithSpan(
|
||||||
|
"parent",
|
||||||
|
() ->
|
||||||
|
stageSessionFactory
|
||||||
|
.withSession(
|
||||||
|
session ->
|
||||||
|
session
|
||||||
|
.find(Value.class, 1L)
|
||||||
|
.thenAccept(
|
||||||
|
value -> {
|
||||||
|
testing.runWithSpan("callback", () -> {});
|
||||||
|
}))
|
||||||
|
.toCompletableFuture())
|
||||||
|
.get(30, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
assertTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertTrace() {
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL),
|
||||||
|
span ->
|
||||||
|
span.hasName("SELECT tempdb.Value")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasParent(trace.getSpan(0))
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(DB_NAME, DB),
|
||||||
|
equalTo(DB_USER, USER_DB),
|
||||||
|
equalTo(
|
||||||
|
DB_STATEMENT,
|
||||||
|
"select v1_0.id,v1_0.name from Value v1_0 where v1_0.id=$?"),
|
||||||
|
equalTo(DB_OPERATION, "SELECT"),
|
||||||
|
equalTo(DB_SQL_TABLE, "Value"),
|
||||||
|
equalTo(NET_PEER_NAME, "localhost"),
|
||||||
|
equalTo(NET_PEER_PORT, port)),
|
||||||
|
span ->
|
||||||
|
span.hasName("callback")
|
||||||
|
.hasKind(SpanKind.INTERNAL)
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v2_0;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table
|
||||||
|
public class Value {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Value() {}
|
||||||
|
|
||||||
|
public Value(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String title) {
|
||||||
|
name = title;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||||
|
version="2.0">
|
||||||
|
|
||||||
|
<persistence-unit name="test-pu">
|
||||||
|
<provider>org.hibernate.reactive.provider.ReactivePersistenceProvider</provider>
|
||||||
|
<class>io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v2_0.Value</class>
|
||||||
|
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
|
||||||
|
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://localhost:${db.port}/tempdb"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.user" value="SA"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.password" value="password123"/>
|
||||||
|
<property name="hibernate.connection.pool_size" value="10"/>
|
||||||
|
<property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/>
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
</persistence>
|
|
@ -5,36 +5,53 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql;
|
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql;
|
||||||
|
|
||||||
|
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||||
|
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.setSqlConnectOptions;
|
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.setSqlConnectOptions;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isStatic;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.util.VirtualField;
|
||||||
import io.opentelemetry.javaagent.bootstrap.CallDepth;
|
import io.opentelemetry.javaagent.bootstrap.CallDepth;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import io.vertx.core.Future;
|
||||||
import io.vertx.sqlclient.Pool;
|
import io.vertx.sqlclient.Pool;
|
||||||
import io.vertx.sqlclient.SqlConnectOptions;
|
import io.vertx.sqlclient.SqlConnectOptions;
|
||||||
|
import io.vertx.sqlclient.SqlConnection;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
public class PoolInstrumentation implements TypeInstrumentation {
|
public class PoolInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||||
|
return hasClassesNamed("io.vertx.sqlclient.Pool");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
return named("io.vertx.sqlclient.Pool");
|
return implementsInterface(named("io.vertx.sqlclient.Pool"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transform(TypeTransformer transformer) {
|
public void transform(TypeTransformer transformer) {
|
||||||
transformer.applyAdviceToMethod(
|
transformer.applyAdviceToMethod(
|
||||||
named("pool")
|
named("pool")
|
||||||
|
.and(isStatic())
|
||||||
.and(takesArguments(3))
|
.and(takesArguments(3))
|
||||||
.and(takesArgument(1, named("io.vertx.sqlclient.SqlConnectOptions")))
|
.and(takesArgument(1, named("io.vertx.sqlclient.SqlConnectOptions")))
|
||||||
.and(returns(named("io.vertx.sqlclient.Pool"))),
|
.and(returns(named("io.vertx.sqlclient.Pool"))),
|
||||||
PoolInstrumentation.class.getName() + "$PoolAdvice");
|
PoolInstrumentation.class.getName() + "$PoolAdvice");
|
||||||
|
|
||||||
|
transformer.applyAdviceToMethod(
|
||||||
|
named("getConnection").and(takesNoArguments()).and(returns(named("io.vertx.core.Future"))),
|
||||||
|
PoolInstrumentation.class.getName() + "$GetConnectionAdvice");
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -53,12 +70,33 @@ public class PoolInstrumentation implements TypeInstrumentation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
public static void onExit(@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
public static void onExit(
|
||||||
|
@Advice.Return Pool pool,
|
||||||
|
@Advice.Argument(1) SqlConnectOptions sqlConnectOptions,
|
||||||
|
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||||
if (callDepth.decrementAndGet() > 0) {
|
if (callDepth.decrementAndGet() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VirtualField<Pool, SqlConnectOptions> virtualField =
|
||||||
|
VirtualField.find(Pool.class, SqlConnectOptions.class);
|
||||||
|
virtualField.set(pool, sqlConnectOptions);
|
||||||
|
|
||||||
setSqlConnectOptions(null);
|
setSqlConnectOptions(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static class GetConnectionAdvice {
|
||||||
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
|
public static void onExit(
|
||||||
|
@Advice.This Pool pool, @Advice.Return(readOnly = false) Future<SqlConnection> future) {
|
||||||
|
// copy connect options stored on pool to new connection
|
||||||
|
VirtualField<Pool, SqlConnectOptions> virtualField =
|
||||||
|
VirtualField.find(Pool.class, SqlConnectOptions.class);
|
||||||
|
SqlConnectOptions sqlConnectOptions = virtualField.get(pool);
|
||||||
|
|
||||||
|
future = VertxSqlClientSingletons.attachConnectOptions(future, sqlConnectOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ public class SqlClientBaseInstrumentation implements TypeInstrumentation {
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
public static void onExit(@Advice.This SqlClientBase<?> sqlClientBase) {
|
public static void onExit(@Advice.This SqlClientBase<?> sqlClientBase) {
|
||||||
// copy connection options from ThreadLocal to VirtualField
|
// copy connection options from ThreadLocal to VirtualField
|
||||||
|
// this virtual field is also set in VertxSqlClientSingletons.attachConnectOptions
|
||||||
VirtualField<SqlClientBase<?>, SqlConnectOptions> virtualField =
|
VirtualField<SqlClientBase<?>, SqlConnectOptions> virtualField =
|
||||||
VirtualField.find(SqlClientBase.class, SqlConnectOptions.class);
|
VirtualField.find(SqlClientBase.class, SqlConnectOptions.class);
|
||||||
virtualField.set(sqlClientBase, getSqlConnectOptions());
|
virtualField.set(sqlClientBase, getSqlConnectOptions());
|
||||||
|
|
|
@ -16,8 +16,12 @@ import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtr
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.db.SqlClientAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.db.SqlClientAttributesExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.net.PeerServiceAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.net.PeerServiceAttributesExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.network.ServerAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.network.ServerAttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.util.VirtualField;
|
||||||
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
|
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
|
||||||
|
import io.vertx.core.Future;
|
||||||
import io.vertx.sqlclient.SqlConnectOptions;
|
import io.vertx.sqlclient.SqlConnectOptions;
|
||||||
|
import io.vertx.sqlclient.SqlConnection;
|
||||||
|
import io.vertx.sqlclient.impl.SqlClientBase;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public final class VertxSqlClientSingletons {
|
public final class VertxSqlClientSingletons {
|
||||||
|
@ -74,5 +78,20 @@ public final class VertxSqlClientSingletons {
|
||||||
return otelParentContext.makeCurrent();
|
return otelParentContext.makeCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this virtual field is also used in SqlClientBase instrumentation
|
||||||
|
private static final VirtualField<SqlClientBase<?>, SqlConnectOptions> connectOptionsField =
|
||||||
|
VirtualField.find(SqlClientBase.class, SqlConnectOptions.class);
|
||||||
|
|
||||||
|
public static Future<SqlConnection> attachConnectOptions(
|
||||||
|
Future<SqlConnection> future, SqlConnectOptions connectOptions) {
|
||||||
|
return future.map(
|
||||||
|
sqlConnection -> {
|
||||||
|
if (sqlConnection instanceof SqlClientBase) {
|
||||||
|
connectOptionsField.set((SqlClientBase<?>) sqlConnection, connectOptions);
|
||||||
|
}
|
||||||
|
return sqlConnection;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private VertxSqlClientSingletons() {}
|
private VertxSqlClientSingletons() {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue