Skip to content

Commit

Permalink
Add instrumentation for hibernate reactive (#9304)
Browse files Browse the repository at this point in the history
  • Loading branch information
laurit authored Aug 25, 2023
1 parent 575627d commit 4baa694
Show file tree
Hide file tree
Showing 15 changed files with 356 additions and 71 deletions.
3 changes: 2 additions & 1 deletion docs/supported-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ or [contributing](../CONTRIBUTING.md).
These are the supported libraries and frameworks:

| Library/Framework | Auto-instrumented versions | Standalone Library Instrumentation [1] | Semantic Conventions |
| ------------------------------------------------------------------------------------------------------------------------------------------- |-------------------------------| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|---------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| [Akka Actors](https://doc.akka.io/docs/akka/current/typed/index.html) | 2.5+ | N/A | Context propagation |
| [Akka HTTP](https://doc.akka.io/docs/akka-http/current/index.html) | 10.0+ | N/A | [HTTP Client Spans], [HTTP Client Metrics], [HTTP Server Spans], [HTTP Server Metrics] |
| [Apache Axis2](https://axis.apache.org/axis2/java/core/) | 1.6+ | N/A | Provides `http.route` [2], Controller Spans [3] |
Expand Down Expand Up @@ -65,6 +65,7 @@ These are the supported libraries and frameworks:
| [Guava ListenableFuture](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/ListenableFuture.html) | 10.0+ | [opentelemetry-guava-10.0](../instrumentation/guava-10.0/library) | Context propagation |
| [GWT](http://www.gwtproject.org/) | 2.0+ | N/A | [RPC Server Spans] |
| [Hibernate](https://github.com/hibernate/hibernate-orm) | 3.3+ | N/A | none |
| [Hibernate Reactive](https://hibernate.org/reactive) | 1.0+ | N/A | none |
| [HikariCP](https://github.com/brettwooldridge/HikariCP) | 3.0+ | [opentelemetry-hikaricp-3.0](../instrumentation/hikaricp-3.0/library) | [Database Pool Metrics] |
| [HttpURLConnection](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpURLConnection.html) | Java 8+ | N/A | [HTTP Client Spans], [HTTP Client Metrics] |
| [Hystrix](https://github.com/Netflix/Hystrix) | 1.4+ | N/A | none |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("org.hibernate.reactive")
module.set("hibernate-reactive-core")
versions.set("(,)")
assertInverse.set(true)
}
}

dependencies {
compileOnly("org.hibernate.reactive:hibernate-reactive-core:1.0.0.Final")

testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent"))
testInstrumentation(project(":instrumentation:vertx:vertx-sql-client-4.0:javaagent"))

library("io.vertx:vertx-sql-client:4.4.2")
compileOnly("io.vertx:vertx-codegen:4.4.2")

testLibrary("io.vertx:vertx-pg-client:4.4.2")
testLibrary("io.vertx:vertx-codegen:4.4.2")
}

val latestDepTest = findProperty("testLatestDeps") as Boolean

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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
Expand Down Expand Up @@ -98,10 +99,15 @@ void testMutiny() {
() -> {
mutinySessionFactory
.withSession(
session ->
session
.find(Value.class, 1L)
.invoke(value -> testing.runWithSpan("callback", () -> {})))
session -> {
if (!Span.current().getSpanContext().isValid()) {
throw new IllegalStateException("missing parent span");
}

return session
.find(Value.class, 1L)
.invoke(value -> testing.runWithSpan("callback", () -> {}));
})
.await()
.atMost(Duration.ofSeconds(30));
});
Expand All @@ -117,10 +123,15 @@ void testStage() throws Exception {
() ->
stageSessionFactory
.withSession(
session ->
session
.find(Value.class, 1L)
.thenAccept(value -> testing.runWithSpan("callback", () -> {})))
session -> {
if (!Span.current().getSpanContext().isValid()) {
throw new IllegalStateException("missing parent span");
}

return session
.find(Value.class, 1L)
.thenAccept(value -> testing.runWithSpan("callback", () -> {}));
})
.toCompletableFuture())
.get(30, TimeUnit.SECONDS);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
Expand Down Expand Up @@ -98,10 +99,15 @@ void testMutiny() {
() -> {
mutinySessionFactory
.withSession(
session ->
session
.find(Value.class, 1L)
.invoke(value -> testing.runWithSpan("callback", () -> {})))
session -> {
if (!Span.current().getSpanContext().isValid()) {
throw new IllegalStateException("missing parent span");
}

return session
.find(Value.class, 1L)
.invoke(value -> testing.runWithSpan("callback", () -> {}));
})
.await()
.atMost(Duration.ofSeconds(30));
});
Expand All @@ -117,10 +123,15 @@ void testStage() throws Exception {
() ->
stageSessionFactory
.withSession(
session ->
session
.find(Value.class, 1L)
.thenAccept(value -> testing.runWithSpan("callback", () -> {})))
session -> {
if (!Span.current().getSpanContext().isValid()) {
throw new IllegalStateException("missing parent span");
}

return session
.find(Value.class, 1L)
.thenAccept(value -> testing.runWithSpan("callback", () -> {}));
})
.toCompletableFuture())
.get(30, TimeUnit.SECONDS);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v1_0;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.operators.UniOperator;
import io.smallrye.mutiny.subscription.UniSubscriber;
import io.smallrye.mutiny.subscription.UniSubscription;

public final class ContextOperator<T> extends UniOperator<T, T> {
private final Context context;

public ContextOperator(Uni<? extends T> upstream, Context context) {
super(upstream);
this.context = context;
}

public static <T> Uni<T> plug(Uni<T> uni) {
if (uni instanceof ContextOperator) {
return uni;
}
Context parentContext = Context.current();
if (parentContext == Context.root()) {
return uni;
}

return uni.plug(u -> new ContextOperator<>(u, parentContext));
}

@Override
public void subscribe(UniSubscriber<? super T> downstream) {
try (Scope ignore = context.makeCurrent()) {
upstream().subscribe().withSubscriber(new ContextSubscriber<>(downstream, context));
}
}

private static class ContextSubscriber<T> implements UniSubscriber<T> {
private final UniSubscriber<? super T> downstream;
private final Context context;

private ContextSubscriber(UniSubscriber<? super T> downstream, Context context) {
this.downstream = downstream;
this.context = context;
}

@Override
public void onSubscribe(UniSubscription uniSubscription) {
try (Scope ignore = context.makeCurrent()) {
downstream.onSubscribe(uniSubscription);
}
}

@Override
public void onItem(T t) {
try (Scope ignore = context.makeCurrent()) {
downstream.onItem(t);
}
}

@Override
public void onFailure(Throwable throwable) {
try (Scope ignore = context.makeCurrent()) {
downstream.onFailure(throwable);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v1_0;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import java.util.function.Function;

public final class FunctionWrapper<T, R> implements Function<T, R> {
private final Function<T, R> delegate;
private final Context context;

private FunctionWrapper(Function<T, R> delegate, Context context) {
this.delegate = delegate;
this.context = context;
}

public static <T, R> Function<T, R> wrap(Function<T, R> function) {
if (function instanceof FunctionWrapper) {
return function;
}
Context context = Context.current();
if (context == Context.root()) {
return function;
}

return new FunctionWrapper<>(function, context);
}

@Override
public R apply(T t) {
try (Scope ignore = context.makeCurrent()) {
return delegate.apply(t);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.hibernate.reactive.v1_0;

import static java.util.Arrays.asList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class HibernateReactiveInstrumentationModule extends InstrumentationModule {

public HibernateReactiveInstrumentationModule() {
super("hibernate-reactive", "hibernate-reactive-1.0");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(
new StageSessionFactoryInstrumentation(), new MutinySessionFactoryInstrumentation());
}
}
Loading

0 comments on commit 4baa694

Please sign in to comment.