make vertx indy-ready (#14567)

This commit is contained in:
SylvainJuge 2025-09-05 14:44:46 +02:00 committed by GitHub
parent d84b144cad
commit 1961f62b95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 604 additions and 404 deletions

View File

@ -5,10 +5,10 @@
package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client; package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.HTTP_CLIENT_OPTIONS;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.instrumentation.api.util.VirtualField;
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.http.HttpClientOptions; import io.vertx.core.http.HttpClientOptions;
@ -36,7 +36,7 @@ public class HttpClientImplInstrumentation implements TypeInstrumentation {
public static void attachHttpClientOptions( public static void attachHttpClientOptions(
@Advice.This HttpClientImpl client, @Advice.This HttpClientImpl client,
@Advice.FieldValue("options") HttpClientOptions options) { @Advice.FieldValue("options") HttpClientOptions options) {
VirtualField.find(HttpClientImpl.class, HttpClientOptions.class).set(client, options); HTTP_CLIENT_OPTIONS.set(client, options);
} }
} }
} }

View File

@ -5,11 +5,12 @@
package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client; package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.HTTP_CLIENT_OPTIONS;
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.REQUEST_INFO;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import io.opentelemetry.instrumentation.api.util.VirtualField;
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.http.HttpClientOptions; import io.vertx.core.http.HttpClientOptions;
@ -53,10 +54,8 @@ public class HttpRequestImplInstrumentation implements TypeInstrumentation {
@Advice.Argument(0) HttpClientImpl client, @Advice.Argument(0) HttpClientImpl client,
@Advice.Argument(2) String host, @Advice.Argument(2) String host,
@Advice.Argument(3) int port) { @Advice.Argument(3) int port) {
HttpClientOptions httpClientOptions = HttpClientOptions httpClientOptions = HTTP_CLIENT_OPTIONS.get(client);
VirtualField.find(HttpClientImpl.class, HttpClientOptions.class).get(client); REQUEST_INFO.set(
VirtualField.find(HttpClientRequest.class, VertxRequestInfo.class)
.set(
request, request,
VertxRequestInfo.create( VertxRequestInfo.create(
httpClientOptions != null && httpClientOptions.isSsl(), host, port)); httpClientOptions != null && httpClientOptions.isSsl(), host, port));
@ -71,8 +70,7 @@ public class HttpRequestImplInstrumentation implements TypeInstrumentation {
@Advice.Argument(1) boolean ssl, @Advice.Argument(1) boolean ssl,
@Advice.Argument(3) String host, @Advice.Argument(3) String host,
@Advice.Argument(4) int port) { @Advice.Argument(4) int port) {
VirtualField.find(HttpClientRequest.class, VertxRequestInfo.class) REQUEST_INFO.set(request, VertxRequestInfo.create(ssl, host, port));
.set(request, VertxRequestInfo.create(ssl, host, port));
} }
} }
@ -84,8 +82,7 @@ public class HttpRequestImplInstrumentation implements TypeInstrumentation {
@Advice.Argument(1) boolean ssl, @Advice.Argument(1) boolean ssl,
@Advice.Argument(4) String host, @Advice.Argument(4) String host,
@Advice.Argument(5) int port) { @Advice.Argument(5) int port) {
VirtualField.find(HttpClientRequest.class, VertxRequestInfo.class) REQUEST_INFO.set(request, VertxRequestInfo.create(ssl, host, port));
.set(request, VertxRequestInfo.create(ssl, host, port));
} }
} }
} }

View File

@ -7,6 +7,8 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.CONTEXTS;
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.REQUEST_INFO;
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.instrumenter; import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPrivate; import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
@ -16,8 +18,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope; import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
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.opentelemetry.javaagent.instrumentation.vertx.client.Contexts; import io.opentelemetry.javaagent.instrumentation.vertx.client.Contexts;
@ -25,7 +25,10 @@ import io.opentelemetry.javaagent.instrumentation.vertx.client.ExceptionHandlerW
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpClientResponse;
import javax.annotation.Nullable;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -83,41 +86,52 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class EndRequestAdvice { public static class EndRequestAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) public static class AdviceScope {
public static void attachContext( private final Context context;
@Advice.This HttpClientRequest request, private final Scope scope;
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
VertxRequestInfo requestInfo = private AdviceScope(Context context, Scope scope) {
VirtualField.find(HttpClientRequest.class, VertxRequestInfo.class).get(request); this.context = context;
this.scope = scope;
}
@Nullable
public static AdviceScope startAndAttachContext(HttpClientRequest request) {
VertxRequestInfo requestInfo = REQUEST_INFO.get(request);
if (requestInfo == null) { if (requestInfo == null) {
return; return null;
} }
Context parentContext = Java8BytecodeBridge.currentContext(); Context parentContext = Context.current();
if (!instrumenter().shouldStart(parentContext, request)) { if (!instrumenter().shouldStart(parentContext, request)) {
return; return null;
}
Context context = instrumenter().start(parentContext, request);
CONTEXTS.set(request, new Contexts(parentContext, context));
return new AdviceScope(context, context.makeCurrent());
} }
context = instrumenter().start(parentContext, request); public void end(@Nullable Throwable throwable, HttpClientRequest request) {
Contexts contexts = new Contexts(parentContext, context); scope.close();
VirtualField.find(HttpClientRequest.class, Contexts.class).set(request, contexts); if (throwable != null) {
instrumenter().end(context, request, null, throwable);
}
}
}
scope = context.makeCurrent(); @Nullable
@Advice.OnMethodEnter(suppress = Throwable.class)
public static AdviceScope attachContext(@Advice.This HttpClientRequest request) {
return AdviceScope.startAndAttachContext(request);
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endScope( public static void endScope(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request,
@Advice.Local("otelContext") Context context, @Advice.Thrown @Nullable Throwable throwable,
@Advice.Local("otelScope") Scope scope, @Advice.Enter @Nullable AdviceScope adviceScope) {
@Advice.Thrown Throwable throwable) { if (adviceScope != null) {
if (scope != null) { adviceScope.end(throwable, request);
scope.close();
}
if (throwable != null) {
instrumenter().end(context, request, null, throwable);
} }
} }
} }
@ -125,25 +139,23 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class HandleExceptionAdvice { public static class HandleExceptionAdvice {
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void handleException( public static Scope handleException(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request, @Advice.Argument(0) Throwable t) {
@Advice.Argument(0) Throwable t,
@Advice.Local("otelScope") Scope scope) {
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
Contexts contexts = CONTEXTS.get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
instrumenter().end(contexts.context, request, null, t); instrumenter().end(contexts.context, request, null, t);
// Scoping all potential callbacks etc to the parent context // Scoping all potential callbacks etc to the parent context
scope = contexts.parentContext.makeCurrent(); return contexts.parentContext.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void handleResponseExit(@Advice.Local("otelScope") Scope scope) { public static void handleResponseExit(@Advice.Enter @Nullable Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -153,25 +165,23 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class HandleResponseAdvice { public static class HandleResponseAdvice {
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void handleResponseEnter( public static Scope handleResponseEnter(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request, @Advice.Argument(0) HttpClientResponse response) {
@Advice.Argument(0) HttpClientResponse response,
@Advice.Local("otelScope") Scope scope) {
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
Contexts contexts = CONTEXTS.get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
instrumenter().end(contexts.context, request, response, null); instrumenter().end(contexts.context, request, response, null);
// Scoping all potential callbacks etc to the parent context // Scoping all potential callbacks etc to the parent context
scope = contexts.parentContext.makeCurrent(); return contexts.parentContext.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void handleResponseExit(@Advice.Local("otelScope") Scope scope) { public static void handleResponseExit(@Advice.Enter @Nullable Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -181,19 +191,18 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class MountContextAdvice { public static class MountContextAdvice {
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void mountContext( public static Scope mountContext(@Advice.This HttpClientRequest request) {
@Advice.This HttpClientRequest request, @Advice.Local("otelScope") Scope scope) { Contexts contexts = CONTEXTS.get(request);
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
return contexts.context.makeCurrent();
scope = contexts.context.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void unmountContext(@Advice.Local("otelScope") Scope scope) { public static void unmountContext(@Advice.Enter @Nullable Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -203,15 +212,16 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class ExceptionHandlerAdvice { public static class ExceptionHandlerAdvice {
@Nullable
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapExceptionHandler( public static Handler<Throwable> wrapExceptionHandler(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request,
@Advice.Argument(value = 0, readOnly = false) Handler<Throwable> handler) { @Advice.Argument(0) @Nullable Handler<Throwable> handler) {
if (handler != null) { if (handler == null) {
VirtualField<HttpClientRequest, Contexts> virtualField = return null;
VirtualField.find(HttpClientRequest.class, Contexts.class); }
handler = ExceptionHandlerWrapper.wrap(instrumenter(), request, virtualField, handler); return ExceptionHandlerWrapper.wrap(instrumenter(), request, CONTEXTS, handler);
}
} }
} }
} }

View File

@ -11,11 +11,13 @@ import static java.util.Arrays.asList;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
import java.util.List; import java.util.List;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@AutoService(InstrumentationModule.class) @AutoService(InstrumentationModule.class)
public class VertxClientInstrumentationModule extends InstrumentationModule { public class VertxClientInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public VertxClientInstrumentationModule() { public VertxClientInstrumentationModule() {
super("vertx-http-client", "vertx-http-client-3.0", "vertx"); super("vertx-http-client", "vertx-http-client-3.0", "vertx");
@ -34,4 +36,9 @@ public class VertxClientInstrumentationModule extends InstrumentationModule {
new HttpRequestImplInstrumentation(), new HttpRequestImplInstrumentation(),
new HttpRequestInstrumentation()); new HttpRequestInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -6,9 +6,13 @@
package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client; package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.javaagent.instrumentation.vertx.client.Contexts;
import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory; import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpClientResponse;
import io.vertx.core.http.impl.HttpClientImpl;
public final class VertxClientSingletons { public final class VertxClientSingletons {
@ -16,6 +20,15 @@ public final class VertxClientSingletons {
VertxClientInstrumenterFactory.create( VertxClientInstrumenterFactory.create(
"io.opentelemetry.vertx-http-client-3.0", new Vertx3HttpAttributesGetter()); "io.opentelemetry.vertx-http-client-3.0", new Vertx3HttpAttributesGetter());
public static final VirtualField<HttpClientRequest, Contexts> CONTEXTS =
VirtualField.find(HttpClientRequest.class, Contexts.class);
public static final VirtualField<HttpClientRequest, VertxRequestInfo> REQUEST_INFO =
VirtualField.find(HttpClientRequest.class, VertxRequestInfo.class);
public static final VirtualField<HttpClientImpl, HttpClientOptions> HTTP_CLIENT_OPTIONS =
VirtualField.find(HttpClientImpl.class, HttpClientOptions.class);
public static Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter() { public static Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter() {
return INSTRUMENTER; return INSTRUMENTER;
} }

View File

@ -12,7 +12,10 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
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.Handler; import io.vertx.core.Handler;
import javax.annotation.Nullable;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -42,28 +45,31 @@ public class ConnectionManagerInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class GetConnectionArg2Advice { public static class GetConnectionArg2Advice {
@Nullable
@AssignReturned.ToArguments(@ToArgument(2))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler( public static Handler<?> wrapHandler(@Advice.Argument(2) @Nullable Handler<?> handler) {
@Advice.Argument(value = 2, readOnly = false) Handler<?> handler) { return HandlerWrapper.wrap(handler);
handler = HandlerWrapper.wrap(handler);
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class GetConnectionArg3Advice { public static class GetConnectionArg3Advice {
@Nullable
@AssignReturned.ToArguments(@ToArgument(3))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler( public static Handler<?> wrapHandler(@Advice.Argument(3) @Nullable Handler<?> handler) {
@Advice.Argument(value = 3, readOnly = false) Handler<?> handler) { return HandlerWrapper.wrap(handler);
handler = HandlerWrapper.wrap(handler);
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class GetConnectionArg4Advice { public static class GetConnectionArg4Advice {
@Nullable
@AssignReturned.ToArguments(@ToArgument(4))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler( public static Handler<?> wrapHandler(@Advice.Argument(4) @Nullable Handler<?> handler) {
@Advice.Argument(value = 4, readOnly = false) Handler<?> handler) { return HandlerWrapper.wrap(handler);
handler = HandlerWrapper.wrap(handler);
} }
} }
} }

View File

@ -8,6 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope; import io.opentelemetry.context.Scope;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import javax.annotation.Nullable;
public class HandlerWrapper<T> implements Handler<T> { public class HandlerWrapper<T> implements Handler<T> {
private final Handler<T> delegate; private final Handler<T> delegate;
@ -18,7 +19,8 @@ public class HandlerWrapper<T> implements Handler<T> {
this.context = context; this.context = context;
} }
public static <T> Handler<T> wrap(Handler<T> handler) { @Nullable
public static <T> Handler<T> wrap(@Nullable Handler<T> handler) {
Context current = Context.current(); Context current = Context.current();
if (handler != null && !(handler instanceof HandlerWrapper) && current != Context.root()) { if (handler != null && !(handler instanceof HandlerWrapper) && current != Context.root()) {
handler = new HandlerWrapper<>(handler, current); handler = new HandlerWrapper<>(handler, current);

View File

@ -14,6 +14,8 @@ 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.Handler; import io.vertx.core.Handler;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -39,10 +41,10 @@ public class HttpClientConnectionInstrumentation implements TypeInstrumentation
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class CreateStreamAdvice { public static class CreateStreamAdvice {
@AssignReturned.ToArguments(@ToArgument(1))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler( public static Handler<?> wrapHandler(@Advice.Argument(1) Handler<?> handler) {
@Advice.Argument(value = 1, readOnly = false) Handler<?> handler) { return HandlerWrapper.wrap(handler);
handler = HandlerWrapper.wrap(handler);
} }
} }
} }

View File

@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client.VertxClientSingletons.CONTEXTS;
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client.VertxClientSingletons.instrumenter; import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client.VertxClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPrivate; import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
@ -16,8 +17,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope; import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
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.opentelemetry.javaagent.instrumentation.vertx.client.Contexts; import io.opentelemetry.javaagent.instrumentation.vertx.client.Contexts;
@ -25,7 +24,10 @@ import io.opentelemetry.javaagent.instrumentation.vertx.client.ExceptionHandlerW
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpClientResponse;
import javax.annotation.Nullable;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -85,35 +87,50 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class EndRequestAdvice { public static class EndRequestAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) public static class AdviceScope {
public static void attachContext( private final Context context;
@Advice.This HttpClientRequest request, private final Scope scope;
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = Java8BytecodeBridge.currentContext();
if (!instrumenter().shouldStart(parentContext, request)) { private AdviceScope(Context context, Scope scope) {
return; this.context = context;
this.scope = scope;
} }
context = instrumenter().start(parentContext, request); @Nullable
Contexts contexts = new Contexts(parentContext, context); public static AdviceScope startAndAttachContext(HttpClientRequest request) {
VirtualField.find(HttpClientRequest.class, Contexts.class).set(request, contexts); Context parentContext = Context.current();
if (!instrumenter().shouldStart(parentContext, request)) {
return null;
}
scope = context.makeCurrent(); Context context = instrumenter().start(parentContext, request);
Contexts contexts = new Contexts(parentContext, context);
CONTEXTS.set(request, contexts);
return new AdviceScope(context, context.makeCurrent());
}
public void end(HttpClientRequest request, Throwable throwable) {
scope.close();
if (throwable != null) {
instrumenter().end(context, request, null, throwable);
}
}
}
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class)
public static AdviceScope attachContext(@Advice.This HttpClientRequest request) {
return AdviceScope.startAndAttachContext(request);
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endScope( public static void endScope(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request,
@Advice.Local("otelContext") Context context, @Advice.Thrown Throwable throwable,
@Advice.Local("otelScope") Scope scope, @Advice.Enter @Nullable AdviceScope adviceScope) {
@Advice.Thrown Throwable throwable) { if (adviceScope != null) {
if (scope != null) { adviceScope.end(request, throwable);
scope.close();
}
if (throwable != null) {
instrumenter().end(context, request, null, throwable);
} }
} }
} }
@ -121,25 +138,24 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class HandleExceptionAdvice { public static class HandleExceptionAdvice {
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void handleException( public static Scope handleException(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request, @Advice.Argument(0) Throwable t) {
@Advice.Argument(0) Throwable t, Contexts contexts = CONTEXTS.get(request);
@Advice.Local("otelScope") Scope scope) {
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
instrumenter().end(contexts.context, request, null, t); instrumenter().end(contexts.context, request, null, t);
// Scoping all potential callbacks etc to the parent context // Scoping all potential callbacks etc to the parent context
scope = contexts.parentContext.makeCurrent(); return contexts.parentContext.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void handleResponseExit(@Advice.Local("otelScope") Scope scope) { public static void handleResponseExit(@Advice.Enter @Nullable Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -149,25 +165,24 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class HandleResponseAdvice { public static class HandleResponseAdvice {
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void handleResponseEnter( public static Scope handleResponseEnter(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request, @Advice.Argument(1) HttpClientResponse response) {
@Advice.Argument(1) HttpClientResponse response, Contexts contexts = CONTEXTS.get(request);
@Advice.Local("otelScope") Scope scope) {
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
instrumenter().end(contexts.context, request, response, null); instrumenter().end(contexts.context, request, response, null);
// Scoping all potential callbacks etc to the parent context // Scoping all potential callbacks etc to the parent context
scope = contexts.parentContext.makeCurrent(); return contexts.parentContext.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void handleResponseExit(@Advice.Local("otelScope") Scope scope) { public static void handleResponseExit(@Advice.Enter @Nullable Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -177,19 +192,19 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class MountContextAdvice { public static class MountContextAdvice {
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void mountContext( public static Scope mountContext(@Advice.This HttpClientRequest request) {
@Advice.This HttpClientRequest request, @Advice.Local("otelScope") Scope scope) { Contexts contexts = CONTEXTS.get(request);
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
scope = contexts.context.makeCurrent(); return contexts.context.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void unmountContext(@Advice.Local("otelScope") Scope scope) { public static void unmountContext(@Advice.Enter @Nullable Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -199,15 +214,16 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class ExceptionHandlerAdvice { public static class ExceptionHandlerAdvice {
@Nullable
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapExceptionHandler( public static Handler<Throwable> wrapExceptionHandler(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request,
@Advice.Argument(value = 0, readOnly = false) Handler<Throwable> handler) { @Advice.Argument(0) @Nullable Handler<Throwable> handler) {
if (handler != null) { if (handler == null) {
VirtualField<HttpClientRequest, Contexts> virtualField = return null;
VirtualField.find(HttpClientRequest.class, Contexts.class); }
handler = ExceptionHandlerWrapper.wrap(instrumenter(), request, virtualField, handler); return ExceptionHandlerWrapper.wrap(instrumenter(), request, CONTEXTS, handler);
}
} }
} }
} }

View File

@ -12,11 +12,13 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
import java.util.List; import java.util.List;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@AutoService(InstrumentationModule.class) @AutoService(InstrumentationModule.class)
public class VertxClientInstrumentationModule extends InstrumentationModule { public class VertxClientInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public VertxClientInstrumentationModule() { public VertxClientInstrumentationModule() {
super("vertx-http-client", "vertx-http-client-4.0", "vertx"); super("vertx-http-client", "vertx-http-client-4.0", "vertx");
@ -37,4 +39,9 @@ public class VertxClientInstrumentationModule extends InstrumentationModule {
new HttpClientConnectionInstrumentation(), new HttpClientConnectionInstrumentation(),
new HttpRequestInstrumentation()); new HttpRequestInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -6,6 +6,8 @@
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client; package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.javaagent.instrumentation.vertx.client.Contexts;
import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory; import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpClientResponse;
@ -16,6 +18,9 @@ public final class VertxClientSingletons {
VertxClientInstrumenterFactory.create( VertxClientInstrumenterFactory.create(
"io.opentelemetry.vertx-http-client-4.0", new Vertx4HttpAttributesGetter()); "io.opentelemetry.vertx-http-client-4.0", new Vertx4HttpAttributesGetter());
public static final VirtualField<HttpClientRequest, Contexts> CONTEXTS =
VirtualField.find(HttpClientRequest.class, Contexts.class);
public static Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter() { public static Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter() {
return INSTRUMENTER; return INSTRUMENTER;
} }

View File

@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.client;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.client.VertxClientSingletons.CONTEXTS;
import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.client.VertxClientSingletons.instrumenter; import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.client.VertxClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPrivate; import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
@ -16,8 +17,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope; import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
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.opentelemetry.javaagent.instrumentation.vertx.client.Contexts; import io.opentelemetry.javaagent.instrumentation.vertx.client.Contexts;
@ -25,7 +24,10 @@ import io.opentelemetry.javaagent.instrumentation.vertx.client.ExceptionHandlerW
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpClientResponse;
import javax.annotation.Nullable;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -85,35 +87,47 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class EndRequestAdvice { public static class EndRequestAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) public static class AdviceScope {
public static void attachContext( private final Context context;
@Advice.This HttpClientRequest request, private final Scope scope;
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = Java8BytecodeBridge.currentContext();
if (!instrumenter().shouldStart(parentContext, request)) { private AdviceScope(Context context, Scope scope) {
return; this.context = context;
this.scope = scope;
} }
context = instrumenter().start(parentContext, request); @Nullable
Contexts contexts = new Contexts(parentContext, context); public static AdviceScope startAndAttachContext(HttpClientRequest request) {
VirtualField.find(HttpClientRequest.class, Contexts.class).set(request, contexts); Context parentContext = Context.current();
if (!instrumenter().shouldStart(parentContext, request)) {
return null;
}
Context context = instrumenter().start(parentContext, request);
CONTEXTS.set(request, new Contexts(parentContext, context));
return new AdviceScope(context, context.makeCurrent());
}
scope = context.makeCurrent(); public void end(HttpClientRequest request, @Nullable Throwable throwable) {
scope.close();
if (throwable != null) {
instrumenter().end(context, request, null, throwable);
}
}
}
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class)
public static AdviceScope attachContext(@Advice.This HttpClientRequest request) {
return AdviceScope.startAndAttachContext(request);
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endScope( public static void endScope(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request,
@Advice.Local("otelContext") Context context, @Advice.Thrown @Nullable Throwable throwable,
@Advice.Local("otelScope") Scope scope, @Advice.Enter @Nullable AdviceScope adviceScope) {
@Advice.Thrown Throwable throwable) { if (adviceScope != null) {
if (scope != null) { adviceScope.end(request, throwable);
scope.close();
}
if (throwable != null) {
instrumenter().end(context, request, null, throwable);
} }
} }
} }
@ -122,24 +136,21 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
public static class HandleExceptionAdvice { public static class HandleExceptionAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void handleException( public static Scope handleException(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request, @Advice.Argument(0) Throwable t) {
@Advice.Argument(0) Throwable t, Contexts contexts = CONTEXTS.get(request);
@Advice.Local("otelScope") Scope scope) {
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
instrumenter().end(contexts.context, request, null, t); instrumenter().end(contexts.context, request, null, t);
// Scoping all potential callbacks etc to the parent context // Scoping all potential callbacks etc to the parent context
scope = contexts.parentContext.makeCurrent(); return contexts.parentContext.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void handleResponseExit(@Advice.Local("otelScope") Scope scope) { public static void handleResponseExit(@Advice.Enter Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -150,24 +161,22 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
public static class HandleResponseAdvice { public static class HandleResponseAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void handleResponseEnter( public static Scope handleResponseEnter(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request, @Advice.Argument(1) HttpClientResponse response) {
@Advice.Argument(1) HttpClientResponse response, Contexts contexts = CONTEXTS.get(request);
@Advice.Local("otelScope") Scope scope) {
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
instrumenter().end(contexts.context, request, response, null); instrumenter().end(contexts.context, request, response, null);
// Scoping all potential callbacks etc to the parent context // Scoping all potential callbacks etc to the parent context
scope = contexts.parentContext.makeCurrent(); return contexts.parentContext.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void handleResponseExit(@Advice.Local("otelScope") Scope scope) { public static void handleResponseExit(@Advice.Enter Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -178,18 +187,17 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
public static class MountContextAdvice { public static class MountContextAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void mountContext( public static Scope mountContext(@Advice.This HttpClientRequest request) {
@Advice.This HttpClientRequest request, @Advice.Local("otelScope") Scope scope) { Contexts contexts = CONTEXTS.get(request);
Contexts contexts = VirtualField.find(HttpClientRequest.class, Contexts.class).get(request);
if (contexts == null) { if (contexts == null) {
return; return null;
} }
scope = contexts.context.makeCurrent(); return contexts.context.makeCurrent();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void unmountContext(@Advice.Local("otelScope") Scope scope) { public static void unmountContext(@Advice.Enter Scope scope) {
if (scope != null) { if (scope != null) {
scope.close(); scope.close();
} }
@ -199,15 +207,16 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class ExceptionHandlerAdvice { public static class ExceptionHandlerAdvice {
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapExceptionHandler( public static Handler<Throwable> wrapExceptionHandler(
@Advice.This HttpClientRequest request, @Advice.This HttpClientRequest request,
@Advice.Argument(value = 0, readOnly = false) Handler<Throwable> handler) { @Advice.Argument(0) Handler<Throwable> originalHandler) {
Handler<Throwable> handler = originalHandler;
if (handler != null) { if (handler != null) {
VirtualField<HttpClientRequest, Contexts> virtualField = handler = ExceptionHandlerWrapper.wrap(instrumenter(), request, CONTEXTS, handler);
VirtualField.find(HttpClientRequest.class, Contexts.class); }
handler = ExceptionHandlerWrapper.wrap(instrumenter(), request, virtualField, handler); return handler;
}
} }
} }
} }

View File

@ -12,6 +12,7 @@ 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.core.Future;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -32,9 +33,10 @@ public class ResourceManagerInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class WithResourceAsyncAdvice { public static class WithResourceAsyncAdvice {
@AssignReturned.ToReturned
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void wrapFuture(@Advice.Return(readOnly = false) Future<?> future) { public static Future<?> wrapFuture(@Advice.Return Future<?> future) {
future = VertxClientSingletons.wrapFuture(future); return VertxClientSingletons.wrapFuture(future);
} }
} }
} }

View File

@ -11,11 +11,13 @@ import static java.util.Arrays.asList;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
import java.util.List; import java.util.List;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@AutoService(InstrumentationModule.class) @AutoService(InstrumentationModule.class)
public class VertxClientInstrumentationModule extends InstrumentationModule { public class VertxClientInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public VertxClientInstrumentationModule() { public VertxClientInstrumentationModule() {
super("vertx-http-client", "vertx-http-client-5.0", "vertx"); super("vertx-http-client", "vertx-http-client-5.0", "vertx");
@ -34,4 +36,9 @@ public class VertxClientInstrumentationModule extends InstrumentationModule {
new HttpClientRequestBaseInstrumentation(), new HttpClientRequestBaseInstrumentation(),
new ResourceManagerInstrumentation()); new ResourceManagerInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -9,6 +9,7 @@ import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope; import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.javaagent.instrumentation.vertx.client.Contexts;
import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory; import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
@ -29,6 +30,9 @@ public final class VertxClientSingletons {
private static final VirtualField<HttpClientRequest, HostAndPort> authorityField = private static final VirtualField<HttpClientRequest, HostAndPort> authorityField =
VirtualField.find(HttpClientRequest.class, HostAndPort.class); VirtualField.find(HttpClientRequest.class, HostAndPort.class);
public static final VirtualField<HttpClientRequest, Contexts> CONTEXTS =
VirtualField.find(HttpClientRequest.class, Contexts.class);
public static void setAuthority(HttpClientRequest request, HostAndPort authority) { public static void setAuthority(HttpClientRequest request, HostAndPort authority) {
authorityField.set(request, authority); authorityField.set(request, authority);
} }

View File

@ -16,6 +16,8 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.kafka.client.consumer.impl.KafkaReadStreamImpl; import io.vertx.kafka.client.consumer.impl.KafkaReadStreamImpl;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecord;
@ -47,24 +49,26 @@ public class KafkaReadStreamImplInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class HandlerAdvice { public static class HandlerAdvice {
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static <K, V> void onEnter( public static <K, V> Handler<ConsumerRecord<K, V>> onEnter(
@Advice.This KafkaReadStreamImpl<K, V> readStream, @Advice.This KafkaReadStreamImpl<K, V> readStream,
@Advice.Argument(value = 0, readOnly = false) Handler<ConsumerRecord<K, V>> handler) { @Advice.Argument(0) Handler<ConsumerRecord<K, V>> handler) {
handler = new InstrumentedSingleRecordHandler<>(handler); return new InstrumentedSingleRecordHandler<>(handler);
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class BatchHandlerAdvice { public static class BatchHandlerAdvice {
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static <K, V> void onEnter( public static <K, V> Handler<ConsumerRecords<K, V>> onEnter(
@Advice.This KafkaReadStreamImpl<K, V> readStream, @Advice.This KafkaReadStreamImpl<K, V> readStream,
@Advice.Argument(value = 0, readOnly = false) Handler<ConsumerRecords<K, V>> handler) { @Advice.Argument(0) Handler<ConsumerRecords<K, V>> handler) {
handler = new InstrumentedBatchRecordsHandler<>(handler); return new InstrumentedBatchRecordsHandler<>(handler);
} }
} }

View File

@ -10,10 +10,12 @@ import static java.util.Arrays.asList;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
import java.util.List; import java.util.List;
@AutoService(InstrumentationModule.class) @AutoService(InstrumentationModule.class)
public class VertxKafkaInstrumentationModule extends InstrumentationModule { public class VertxKafkaInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public VertxKafkaInstrumentationModule() { public VertxKafkaInstrumentationModule() {
super("vertx-kafka-client", "vertx-kafka-client-3.6", "vertx"); super("vertx-kafka-client", "vertx-kafka-client-3.6", "vertx");
@ -24,4 +26,9 @@ public class VertxKafkaInstrumentationModule extends InstrumentationModule {
return asList( return asList(
new KafkaReadStreamImplInstrumentation(), new KafkaConsumerRecordsImplInstrumentation()); new KafkaReadStreamImplInstrumentation(), new KafkaConsumerRecordsImplInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -5,7 +5,6 @@
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis; package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis.VertxRedisClientSingletons.instrumenter; import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.redis.VertxRedisClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
@ -21,7 +20,9 @@ import io.vertx.redis.client.Response;
import io.vertx.redis.client.impl.RedisStandaloneConnection; import io.vertx.redis.client.impl.RedisStandaloneConnection;
import io.vertx.redis.client.impl.RedisURI; import io.vertx.redis.client.impl.RedisURI;
import io.vertx.redis.client.impl.RequestUtil; import io.vertx.redis.client.impl.RequestUtil;
import javax.annotation.Nullable;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -40,45 +41,47 @@ public class RedisStandaloneConnectionInstrumentation implements TypeInstrumenta
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class SendAdvice { public static class SendAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) public static class AdviceScope {
public static void onEnter( private final VertxRedisClientRequest otelRequest;
@Advice.This RedisStandaloneConnection connection, private final Context context;
@Advice.Argument(0) Request request, private final Scope scope;
@Advice.FieldValue("netSocket") NetSocket netSocket,
@Advice.Local("otelRequest") VertxRedisClientRequest otelRequest, private AdviceScope(VertxRedisClientRequest otelRequest, Context context, Scope scope) {
@Advice.Local("otelContext") Context context, this.otelRequest = otelRequest;
@Advice.Local("otelScope") Scope scope) { this.context = context;
this.scope = scope;
}
@Nullable
public static AdviceScope start(
RedisStandaloneConnection connection, @Nullable Request request, NetSocket netSocket) {
if (request == null) { if (request == null) {
return; return null;
} }
String commandName = VertxRedisClientSingletons.getCommandName(request.command()); String commandName = VertxRedisClientSingletons.getCommandName(request.command());
RedisURI redisUri = VertxRedisClientSingletons.getRedisUri(connection); RedisURI redisUri = VertxRedisClientSingletons.getRedisUri(connection);
if (commandName == null || redisUri == null) { if (commandName == null || redisUri == null) {
return; return null;
} }
otelRequest = VertxRedisClientRequest otelRequest =
new VertxRedisClientRequest( new VertxRedisClientRequest(
commandName, RequestUtil.getArgs(request), redisUri, netSocket); commandName, RequestUtil.getArgs(request), redisUri, netSocket);
Context parentContext = currentContext(); Context parentContext = Context.current();
if (!instrumenter().shouldStart(parentContext, otelRequest)) { if (!instrumenter().shouldStart(parentContext, otelRequest)) {
return; return null;
}
Context context = instrumenter().start(parentContext, otelRequest);
return new AdviceScope(otelRequest, context, context.makeCurrent());
} }
context = instrumenter().start(parentContext, otelRequest); @Nullable
scope = context.makeCurrent(); public Future<Response> end(
} @Nullable Future<Response> responseFuture, @Nullable Throwable throwable) {
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit(
@Advice.Thrown Throwable throwable,
@Advice.Return(readOnly = false) Future<Response> responseFuture,
@Advice.Local("otelRequest") VertxRedisClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) { if (scope == null) {
return; return responseFuture;
} }
scope.close(); scope.close();
@ -88,6 +91,33 @@ public class RedisStandaloneConnectionInstrumentation implements TypeInstrumenta
responseFuture = responseFuture =
VertxRedisClientSingletons.wrapEndSpan(responseFuture, context, otelRequest); VertxRedisClientSingletons.wrapEndSpan(responseFuture, context, otelRequest);
} }
return responseFuture;
}
}
@Nullable
@Advice.OnMethodEnter(suppress = Throwable.class)
public static AdviceScope onEnter(
@Advice.This RedisStandaloneConnection connection,
@Advice.Argument(0) @Nullable Request request,
@Advice.FieldValue("netSocket") NetSocket netSocket) {
return AdviceScope.start(connection, request, netSocket);
}
@Nullable
@AssignReturned.ToReturned
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static Future<Response> onExit(
@Advice.Thrown Throwable throwable,
@Advice.Return @Nullable Future<Response> responseFuture,
@Advice.Enter @Nullable AdviceScope adviceScope) {
if (adviceScope != null) {
return adviceScope.end(responseFuture, throwable);
}
return responseFuture;
} }
} }

View File

@ -39,4 +39,9 @@ public class VertxRedisClientInstrumentationModule extends InstrumentationModule
new RedisConnectionProviderInstrumentation(), new RedisConnectionProviderInstrumentation(),
new CommandImplInstrumentation()); new CommandImplInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -18,6 +18,8 @@ import io.vertx.core.AsyncResult;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import java.util.function.Consumer; import java.util.function.Consumer;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -50,22 +52,22 @@ public class AsyncResultSingleInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class ConstructorWithHandlerAdvice { public static class ConstructorWithHandlerAdvice {
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler( public static Handler<Handler<AsyncResult<?>>> wrapHandler(
@Advice.Argument(value = 0, readOnly = false) Handler<Handler<AsyncResult<?>>> handler) { @Advice.Argument(0) Handler<Handler<AsyncResult<?>>> handler) {
handler = return AsyncResultHandlerWrapper.wrapIfNeeded(handler, Java8BytecodeBridge.currentContext());
AsyncResultHandlerWrapper.wrapIfNeeded(handler, Java8BytecodeBridge.currentContext());
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class ConstructorWithConsumerAdvice { public static class ConstructorWithConsumerAdvice {
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler( public static Consumer<Handler<AsyncResult<?>>> wrapHandler(
@Advice.Argument(value = 0, readOnly = false) Consumer<Handler<AsyncResult<?>>> handler) { @Advice.Argument(0) Consumer<Handler<AsyncResult<?>>> handler) {
handler = return AsyncResultConsumerWrapper.wrapIfNeeded(handler, Java8BytecodeBridge.currentContext());
AsyncResultConsumerWrapper.wrapIfNeeded(handler, Java8BytecodeBridge.currentContext());
} }
} }
} }

View File

@ -10,10 +10,12 @@ import static java.util.Collections.singletonList;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
import java.util.List; import java.util.List;
@AutoService(InstrumentationModule.class) @AutoService(InstrumentationModule.class)
public class VertxRxInstrumentationModule extends InstrumentationModule { public class VertxRxInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public VertxRxInstrumentationModule() { public VertxRxInstrumentationModule() {
super("vertx-rx-java", "vertx-rx-java-3.5", "vertx"); super("vertx-rx-java", "vertx-rx-java-3.5", "vertx");
@ -23,4 +25,9 @@ public class VertxRxInstrumentationModule extends InstrumentationModule {
public List<TypeInstrumentation> typeInstrumentations() { public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new AsyncResultSingleInstrumentation()); return singletonList(new AsyncResultSingleInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -27,6 +27,7 @@ import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.SqlConnectOptions; import io.vertx.sqlclient.SqlConnectOptions;
import io.vertx.sqlclient.SqlConnection; import io.vertx.sqlclient.SqlConnection;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -60,23 +61,22 @@ public class PoolInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class PoolAdvice { public static class PoolAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter( public static CallDepth onEnter(@Advice.Argument(1) SqlConnectOptions sqlConnectOptions) {
@Advice.Argument(1) SqlConnectOptions sqlConnectOptions, CallDepth callDepth = CallDepth.forClass(Pool.class);
@Advice.Local("otelCallDepth") CallDepth callDepth) {
callDepth = CallDepth.forClass(Pool.class);
if (callDepth.getAndIncrement() > 0) { if (callDepth.getAndIncrement() > 0) {
return; return callDepth;
} }
// set connection options to ThreadLocal, they will be read in SqlClientBase constructor // set connection options to ThreadLocal, they will be read in SqlClientBase constructor
setSqlConnectOptions(sqlConnectOptions); setSqlConnectOptions(sqlConnectOptions);
return callDepth;
} }
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit( public static void onExit(
@Advice.Return Pool pool, @Advice.Return Pool pool,
@Advice.Argument(1) SqlConnectOptions sqlConnectOptions, @Advice.Argument(1) SqlConnectOptions sqlConnectOptions,
@Advice.Local("otelCallDepth") CallDepth callDepth) { @Advice.Enter CallDepth callDepth) {
if (callDepth.decrementAndGet() > 0) { if (callDepth.decrementAndGet() > 0) {
return; return;
} }
@ -88,14 +88,13 @@ public class PoolInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class GetConnectionAdvice { public static class GetConnectionAdvice {
@AssignReturned.ToReturned
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit( public static Future<SqlConnection> onExit(
@Advice.This Pool pool, @Advice.Return(readOnly = false) Future<SqlConnection> future) { @Advice.This Pool pool, @Advice.Return Future<SqlConnection> future) {
// copy connect options stored on pool to new connection // copy connect options stored on pool to new connection
SqlConnectOptions sqlConnectOptions = getPoolSqlConnectOptions(pool); SqlConnectOptions sqlConnectOptions = getPoolSqlConnectOptions(pool);
return wrapContext(attachConnectOptions(future, sqlConnectOptions));
future = attachConnectOptions(future, sqlConnectOptions);
future = wrapContext(future);
} }
} }
} }

View File

@ -5,7 +5,6 @@
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions; import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions;
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.instrumenter; import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
@ -22,6 +21,7 @@ import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil;
import io.vertx.core.impl.future.PromiseInternal; import io.vertx.core.impl.future.PromiseInternal;
import io.vertx.sqlclient.impl.PreparedStatement; import io.vertx.sqlclient.impl.PreparedStatement;
import io.vertx.sqlclient.impl.QueryExecutorUtil; import io.vertx.sqlclient.impl.QueryExecutorUtil;
import javax.annotation.Nullable;
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;
@ -54,17 +54,29 @@ public class QueryExecutorInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class QueryAdvice { public static class QueryAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter( public static class AdviceScope {
@Advice.This Object queryExecutor, private final CallDepth callDepth;
@Advice.AllArguments Object[] arguments, @Nullable private final VertxSqlClientRequest otelRequest;
@Advice.Local("otelCallDepth") CallDepth callDepth, @Nullable private final Context context;
@Advice.Local("otelRequest") VertxSqlClientRequest otelRequest, @Nullable private final Scope scope;
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) { private AdviceScope(CallDepth callDepth) {
callDepth = CallDepth.forClass(queryExecutor.getClass()); this(callDepth, null, null, null);
}
private AdviceScope(
CallDepth callDepth, VertxSqlClientRequest otelRequest, Context context, Scope scope) {
this.callDepth = callDepth;
this.otelRequest = otelRequest;
this.context = context;
this.scope = scope;
}
public static AdviceScope start(Object queryExecutor, Object[] arguments) {
CallDepth callDepth = CallDepth.forClass(queryExecutor.getClass());
if (callDepth.getAndIncrement() > 0) { if (callDepth.getAndIncrement() > 0) {
return; return new AdviceScope(callDepth);
} }
// The parameter we need are in different positions, we are not going to have separate // The parameter we need are in different positions, we are not going to have separate
@ -81,36 +93,30 @@ public class QueryExecutorInstrumentation implements TypeInstrumentation {
sql = ((PreparedStatement) argument).sql(); sql = ((PreparedStatement) argument).sql();
} }
} else if (argument instanceof PromiseInternal) { } else if (argument instanceof PromiseInternal) {
promiseInternal = (PromiseInternal) argument; promiseInternal = (PromiseInternal<?>) argument;
} }
} }
if (sql == null || promiseInternal == null) { if (sql == null || promiseInternal == null) {
return; return new AdviceScope(callDepth);
} }
otelRequest = VertxSqlClientRequest otelRequest =
new VertxSqlClientRequest(sql, QueryExecutorUtil.getConnectOptions(queryExecutor)); new VertxSqlClientRequest(sql, QueryExecutorUtil.getConnectOptions(queryExecutor));
Context parentContext = currentContext(); Context parentContext = Context.current();
if (!instrumenter().shouldStart(parentContext, otelRequest)) { if (!instrumenter().shouldStart(parentContext, otelRequest)) {
return; return new AdviceScope(callDepth, null, null, null);
} }
context = instrumenter().start(parentContext, otelRequest); Context context = instrumenter().start(parentContext, otelRequest);
scope = context.makeCurrent();
VertxSqlClientUtil.attachRequest(promiseInternal, otelRequest, context, parentContext); VertxSqlClientUtil.attachRequest(promiseInternal, otelRequest, context, parentContext);
return new AdviceScope(callDepth, otelRequest, context, context.makeCurrent());
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public void end(@Nullable Throwable throwable) {
public static void onExit(
@Advice.Thrown Throwable throwable,
@Advice.Local("otelCallDepth") CallDepth callDepth,
@Advice.Local("otelRequest") VertxSqlClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (callDepth.decrementAndGet() > 0) { if (callDepth.decrementAndGet() > 0) {
return; return;
} }
if (scope == null) { if (scope == null || context == null || otelRequest == null) {
return; return;
} }
@ -121,4 +127,21 @@ public class QueryExecutorInstrumentation implements TypeInstrumentation {
// span will be ended in QueryResultBuilderInstrumentation // span will be ended in QueryResultBuilderInstrumentation
} }
} }
@Advice.OnMethodEnter(suppress = Throwable.class)
public static AdviceScope onEnter(
@Advice.This Object queryExecutor, @Advice.AllArguments Object[] arguments) {
return AdviceScope.start(queryExecutor, arguments);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit(
@Advice.Thrown @Nullable Throwable throwable,
@Advice.Enter @Nullable AdviceScope adviceScope) {
if (adviceScope != null) {
adviceScope.end(throwable);
}
}
}
} }

View File

@ -50,22 +50,21 @@ public class SqlClientBaseInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class QueryAdvice { public static class QueryAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter( public static CallDepth onEnter(@Advice.This SqlClientBase<?> sqlClientBase) {
@Advice.This SqlClientBase<?> sqlClientBase, CallDepth callDepth = CallDepth.forClass(SqlClientBase.class);
@Advice.Local("otelCallDepth") CallDepth callDepth) {
callDepth = CallDepth.forClass(SqlClientBase.class);
if (callDepth.getAndIncrement() > 0) { if (callDepth.getAndIncrement() > 0) {
return; return callDepth;
} }
// set connection options to ThreadLocal, they will be read in QueryExecutor constructor // set connection options to ThreadLocal, they will be read in QueryExecutor constructor
SqlConnectOptions sqlConnectOptions = getSqlConnectOptions(sqlClientBase); SqlConnectOptions sqlConnectOptions = getSqlConnectOptions(sqlClientBase);
setSqlConnectOptions(sqlConnectOptions); setSqlConnectOptions(sqlConnectOptions);
return callDepth;
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit( public static void onExit(
@Advice.Thrown Throwable throwable, @Advice.Local("otelCallDepth") CallDepth callDepth) { @Advice.Thrown Throwable throwable, @Advice.Enter CallDepth callDepth) {
if (callDepth.decrementAndGet() > 0) { if (callDepth.decrementAndGet() > 0) {
return; return;
} }

View File

@ -12,6 +12,7 @@ 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.Handler; import io.vertx.core.Handler;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -31,9 +32,10 @@ public class TransactionImplInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class WrapHandlerAdvice { public static class WrapHandlerAdvice {
@AssignReturned.ToReturned
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void wrapHandler(@Advice.Return(readOnly = false) Handler<?> handler) { public static Handler<?> wrapHandler(@Advice.Return Handler<?> handler) {
handler = HandlerWrapper.wrap(handler); return HandlerWrapper.wrap(handler);
} }
} }
} }

View File

@ -49,4 +49,9 @@ public class VertxSqlClientInstrumentationModule extends InstrumentationModule
new QueryResultBuilderInstrumentation(), new QueryResultBuilderInstrumentation(),
new TransactionImplInstrumentation()); new TransactionImplInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -19,7 +19,6 @@ 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 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;
@ -28,6 +27,7 @@ import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.SqlConnectOptions; import io.vertx.sqlclient.SqlConnectOptions;
import io.vertx.sqlclient.SqlConnection; import io.vertx.sqlclient.SqlConnection;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -60,32 +60,28 @@ public class PoolInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class PoolAdvice { public static class PoolAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter( public static CallDepth onEnter(@Advice.Argument(1) SqlConnectOptions sqlConnectOptions) {
@Advice.Argument(1) SqlConnectOptions sqlConnectOptions, CallDepth callDepth = CallDepth.forClass(Pool.class);
@Advice.Local("otelCallDepth") CallDepth callDepth) {
callDepth = CallDepth.forClass(Pool.class);
if (callDepth.getAndIncrement() > 0) { if (callDepth.getAndIncrement() > 0) {
return; return callDepth;
} }
// set connection options to ThreadLocal, they will be read in SqlClientBase constructor // set connection options to ThreadLocal, they will be read in SqlClientBase constructor
setSqlConnectOptions(sqlConnectOptions); setSqlConnectOptions(sqlConnectOptions);
return callDepth;
} }
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit( public static void onExit(
@Advice.Return Pool pool, @Advice.Return Pool pool,
@Advice.Argument(1) SqlConnectOptions sqlConnectOptions, @Advice.Argument(1) SqlConnectOptions sqlConnectOptions,
@Advice.Local("otelCallDepth") CallDepth callDepth) { @Advice.Enter 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);
setPoolConnectOptions(pool, sqlConnectOptions); setPoolConnectOptions(pool, sqlConnectOptions);
setSqlConnectOptions(null); setSqlConnectOptions(null);
} }
@ -93,14 +89,14 @@ public class PoolInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class GetConnectionAdvice { public static class GetConnectionAdvice {
@AssignReturned.ToReturned
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit( public static Future<SqlConnection> onExit(
@Advice.This Pool pool, @Advice.Return(readOnly = false) Future<SqlConnection> future) { @Advice.This Pool pool, @Advice.Return Future<SqlConnection> future) {
// copy connect options stored on pool to new connection // copy connect options stored on pool to new connection
SqlConnectOptions sqlConnectOptions = getPoolSqlConnectOptions(pool); SqlConnectOptions sqlConnectOptions = getPoolSqlConnectOptions(pool);
future = attachConnectOptions(future, sqlConnectOptions); return wrapContext(attachConnectOptions(future, sqlConnectOptions));
future = wrapContext(future);
} }
} }
} }

View File

@ -5,7 +5,6 @@
package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions; import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions;
import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql.VertxSqlClientSingletons.instrumenter; import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql.VertxSqlClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
@ -22,6 +21,7 @@ import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil;
import io.vertx.core.internal.PromiseInternal; import io.vertx.core.internal.PromiseInternal;
import io.vertx.sqlclient.impl.QueryExecutorUtil; import io.vertx.sqlclient.impl.QueryExecutorUtil;
import io.vertx.sqlclient.internal.PreparedStatement; import io.vertx.sqlclient.internal.PreparedStatement;
import javax.annotation.Nullable;
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;
@ -54,17 +54,28 @@ public class QueryExecutorInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class QueryAdvice { public static class QueryAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) public static class AdviceScope {
public static void onEnter( private final CallDepth callDepth;
@Advice.This Object queryExecutor, @Nullable private final VertxSqlClientRequest otelRequest;
@Advice.AllArguments Object[] arguments, @Nullable private final Context context;
@Advice.Local("otelCallDepth") CallDepth callDepth, @Nullable private final Scope scope;
@Advice.Local("otelRequest") VertxSqlClientRequest otelRequest,
@Advice.Local("otelContext") Context context, private AdviceScope(CallDepth callDepth) {
@Advice.Local("otelScope") Scope scope) { this(callDepth, null, null, null);
callDepth = CallDepth.forClass(queryExecutor.getClass()); }
private AdviceScope(
CallDepth callDepth, VertxSqlClientRequest otelRequest, Context context, Scope scope) {
this.callDepth = callDepth;
this.otelRequest = otelRequest;
this.context = context;
this.scope = scope;
}
public static AdviceScope start(Object queryExecutor, Object[] arguments) {
CallDepth callDepth = CallDepth.forClass(queryExecutor.getClass());
if (callDepth.getAndIncrement() > 0) { if (callDepth.getAndIncrement() > 0) {
return; return new AdviceScope(callDepth);
} }
// The parameter we need are in different positions, we are not going to have separate // The parameter we need are in different positions, we are not going to have separate
@ -81,36 +92,30 @@ public class QueryExecutorInstrumentation implements TypeInstrumentation {
sql = ((PreparedStatement) argument).sql(); sql = ((PreparedStatement) argument).sql();
} }
} else if (argument instanceof PromiseInternal) { } else if (argument instanceof PromiseInternal) {
promiseInternal = (PromiseInternal) argument; promiseInternal = (PromiseInternal<?>) argument;
} }
} }
if (sql == null || promiseInternal == null) { if (sql == null || promiseInternal == null) {
return; return new AdviceScope(callDepth);
} }
otelRequest = VertxSqlClientRequest otelRequest =
new VertxSqlClientRequest(sql, QueryExecutorUtil.getConnectOptions(queryExecutor)); new VertxSqlClientRequest(sql, QueryExecutorUtil.getConnectOptions(queryExecutor));
Context parentContext = currentContext(); Context parentContext = Context.current();
if (!instrumenter().shouldStart(parentContext, otelRequest)) { if (!instrumenter().shouldStart(parentContext, otelRequest)) {
return; return new AdviceScope(callDepth);
} }
context = instrumenter().start(parentContext, otelRequest); Context context = instrumenter().start(parentContext, otelRequest);
scope = context.makeCurrent();
VertxSqlClientUtil.attachRequest(promiseInternal, otelRequest, context, parentContext); VertxSqlClientUtil.attachRequest(promiseInternal, otelRequest, context, parentContext);
return new AdviceScope(callDepth, otelRequest, context, context.makeCurrent());
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public void end(Throwable throwable) {
public static void onExit(
@Advice.Thrown Throwable throwable,
@Advice.Local("otelCallDepth") CallDepth callDepth,
@Advice.Local("otelRequest") VertxSqlClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (callDepth.decrementAndGet() > 0) { if (callDepth.decrementAndGet() > 0) {
return; return;
} }
if (scope == null) { if (scope == null || context == null || otelRequest == null) {
return; return;
} }
@ -121,4 +126,17 @@ public class QueryExecutorInstrumentation implements TypeInstrumentation {
// span will be ended in QueryResultBuilderInstrumentation // span will be ended in QueryResultBuilderInstrumentation
} }
} }
@Advice.OnMethodEnter(suppress = Throwable.class)
public static AdviceScope onEnter(
@Advice.This Object queryExecutor, @Advice.AllArguments Object[] arguments) {
return AdviceScope.start(queryExecutor, arguments);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit(
@Advice.Thrown @Nullable Throwable throwable, @Advice.Enter AdviceScope adviceScope) {
adviceScope.end(throwable);
}
}
} }

View File

@ -50,22 +50,21 @@ public class SqlClientBaseInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class QueryAdvice { public static class QueryAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter( public static CallDepth onEnter(@Advice.This SqlClientBase sqlClientBase) {
@Advice.This SqlClientBase sqlClientBase, CallDepth callDepth = CallDepth.forClass(SqlClientBase.class);
@Advice.Local("otelCallDepth") CallDepth callDepth) {
callDepth = CallDepth.forClass(SqlClientBase.class);
if (callDepth.getAndIncrement() > 0) { if (callDepth.getAndIncrement() > 0) {
return; return callDepth;
} }
// set connection options to ThreadLocal, they will be read in QueryExecutor constructor // set connection options to ThreadLocal, they will be read in QueryExecutor constructor
SqlConnectOptions sqlConnectOptions = getSqlConnectOptions(sqlClientBase); SqlConnectOptions sqlConnectOptions = getSqlConnectOptions(sqlClientBase);
setSqlConnectOptions(sqlConnectOptions); setSqlConnectOptions(sqlConnectOptions);
return callDepth;
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit( public static void onExit(
@Advice.Thrown Throwable throwable, @Advice.Local("otelCallDepth") CallDepth callDepth) { @Advice.Thrown Throwable throwable, @Advice.Enter CallDepth callDepth) {
if (callDepth.decrementAndGet() > 0) { if (callDepth.decrementAndGet() > 0) {
return; return;
} }

View File

@ -12,6 +12,7 @@ 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.Completable; import io.vertx.core.Completable;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -31,9 +32,10 @@ public class TransactionImplInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class WrapHandlerAdvice { public static class WrapHandlerAdvice {
@AssignReturned.ToReturned
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void wrapHandler(@Advice.Return(readOnly = false) Completable<?> handler) { public static Completable<?> wrapHandler(@Advice.Return Completable<?> handler) {
handler = CompletableWrapper.wrap(handler); return CompletableWrapper.wrap(handler);
} }
} }
} }

View File

@ -49,4 +49,9 @@ public class VertxSqlClientInstrumentationModule extends InstrumentationModule
new QueryResultBuilderInstrumentation(), new QueryResultBuilderInstrumentation(),
new TransactionImplInstrumentation()); new TransactionImplInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }

View File

@ -16,6 +16,8 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher;
@ -40,10 +42,11 @@ public class RouteInstrumentation implements TypeInstrumentation {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class HandlerAdvice { public static class HandlerAdvice {
@AssignReturned.ToArguments(@ToArgument(0))
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler( public static Handler<RoutingContext> wrapHandler(
@Advice.Argument(value = 0, readOnly = false) Handler<RoutingContext> handler) { @Advice.Argument(0) Handler<RoutingContext> handler) {
handler = new RoutingContextHandlerWrapper(handler); return new RoutingContextHandlerWrapper(handler);
} }
} }
} }

View File

@ -10,10 +10,12 @@ import static java.util.Arrays.asList;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
import java.util.List; import java.util.List;
@AutoService(InstrumentationModule.class) @AutoService(InstrumentationModule.class)
public class VertxWebInstrumentationModule extends InstrumentationModule { public class VertxWebInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public VertxWebInstrumentationModule() { public VertxWebInstrumentationModule() {
super("vertx-web", "vertx-web-3.0", "vertx"); super("vertx-web", "vertx-web-3.0", "vertx");
@ -23,4 +25,9 @@ public class VertxWebInstrumentationModule extends InstrumentationModule {
public List<TypeInstrumentation> typeInstrumentations() { public List<TypeInstrumentation> typeInstrumentations() {
return asList(new RouteInstrumentation(), new RoutingContextInstrumentation()); return asList(new RouteInstrumentation(), new RoutingContextInstrumentation());
} }
@Override
public boolean isIndyReady() {
return true;
}
} }