diff --git a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java index 0e346e27d9c5..77519a065c91 100644 --- a/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java +++ b/instrumentation/play/play-mvc/play-mvc-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java @@ -11,11 +11,13 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import java.util.List; import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) -public class PlayInstrumentationModule extends InstrumentationModule { +public class PlayInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public PlayInstrumentationModule() { super("play-mvc", "play-mvc-2.4", "play"); @@ -31,4 +33,9 @@ public ElementMatcher.Junction classLoaderMatcher() { public List typeInstrumentations() { return singletonList(new ActionInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/play/play-mvc/play-mvc-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java b/instrumentation/play/play-mvc/play-mvc-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java index ac71cfffd580..dccbd68da2a5 100644 --- a/instrumentation/play/play-mvc/play-mvc-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java +++ b/instrumentation/play/play-mvc/play-mvc-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java @@ -10,10 +10,12 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import java.util.List; @AutoService(InstrumentationModule.class) -public class PlayInstrumentationModule extends InstrumentationModule { +public class PlayInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public PlayInstrumentationModule() { super("play-mvc", "play-mvc-2.6", "play"); @@ -23,4 +25,9 @@ public PlayInstrumentationModule() { public List typeInstrumentations() { return singletonList(new ActionInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/play/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java b/instrumentation/play/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java index 12e49d291119..bc0ae3ec7780 100644 --- a/instrumentation/play/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java +++ b/instrumentation/play/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java @@ -14,17 +14,21 @@ import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation; import io.opentelemetry.javaagent.instrumentation.playws.HandlerPublisherInstrumentation; import java.util.List; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; +import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument; import play.shaded.ahc.org.asynchttpclient.AsyncHandler; import play.shaded.ahc.org.asynchttpclient.Request; import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler; import play.shaded.ahc.org.asynchttpclient.ws.WebSocketUpgradeHandler; @AutoService(InstrumentationModule.class) -public class PlayWsInstrumentationModule extends InstrumentationModule { +public class PlayWsInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public PlayWsInstrumentationModule() { super("play-ws", "play-ws-1.0"); } @@ -37,46 +41,79 @@ public List typeInstrumentations() { new HandlerPublisherInstrumentation()); } + @Override + public boolean isIndyReady() { + return true; + } + @SuppressWarnings("unused") public static class ClientAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void methodEnter( - @Advice.Argument(0) Request request, - @Advice.Argument(value = 1, readOnly = false) AsyncHandler asyncHandler, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - Context parentContext = currentContext(); - if (!instrumenter().shouldStart(parentContext, request)) { - return; + public static class AdviceScope { + private final Context parentContext; + private final Context context; + private final Request request; + private final Scope scope; + + private AdviceScope(Context parentContext, Request request, Context context, Scope scope) { + this.parentContext = parentContext; + this.request = request; + this.context = context; + this.scope = scope; } - context = instrumenter().start(parentContext, request); - scope = context.makeCurrent(); + @Nullable + public static AdviceScope start(Request request) { + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return null; + } + Context context = instrumenter().start(parentContext, request); + return new AdviceScope(parentContext, request, context, context.makeCurrent()); + } - if (asyncHandler instanceof StreamedAsyncHandler) { - asyncHandler = - new StreamedAsyncHandlerWrapper<>( - (StreamedAsyncHandler) asyncHandler, request, context, parentContext); - } else if (!(asyncHandler instanceof WebSocketUpgradeHandler)) { - // websocket upgrade handlers aren't supported - asyncHandler = new AsyncHandlerWrapper<>(asyncHandler, request, context, parentContext); + public AsyncHandler wrap(AsyncHandler handler) { + if (handler instanceof StreamedAsyncHandler) { + return new StreamedAsyncHandlerWrapper<>( + (StreamedAsyncHandler) handler, request, context, parentContext); + } else if (!(handler instanceof WebSocketUpgradeHandler)) { + // websocket upgrade handlers aren't supported + return new AsyncHandlerWrapper<>(handler, request, context, parentContext); + } + return handler; + } + + public void end(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } } } + @Advice.AssignReturned.ToArguments(@ToArgument(value = 1, index = 1)) + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Object[] methodEnter( + @Advice.Argument(0) Request request, + @Advice.Argument(1) AsyncHandler originalAsyncHandler) { + // intermediate variable required for inlined advice + AsyncHandler asyncHandler = originalAsyncHandler; + AdviceScope adviceScope = AdviceScope.start(request); + if (adviceScope != null) { + asyncHandler = adviceScope.wrap(asyncHandler); + } + return new Object[] {adviceScope, asyncHandler}; + } + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Argument(0) Request request, - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - if (scope == null) { - return; - } - scope.close(); + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter Object[] enterResult) { - if (throwable != null) { - instrumenter().end(context, request, null, throwable); + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.end(throwable); } } } diff --git a/instrumentation/play/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java b/instrumentation/play/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java index bf563a1d7e3d..1ceb6ecfe6e9 100644 --- a/instrumentation/play/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java +++ b/instrumentation/play/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java @@ -13,18 +13,23 @@ import io.opentelemetry.context.Context; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import io.opentelemetry.javaagent.instrumentation.playws.AbstractBootstrapInstrumentation; import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation; import io.opentelemetry.javaagent.instrumentation.playws.HandlerPublisherInstrumentation; import java.util.List; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; +import net.bytebuddy.asm.Advice.AssignReturned; +import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument; import play.shaded.ahc.org.asynchttpclient.AsyncHandler; import play.shaded.ahc.org.asynchttpclient.Request; import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler; import play.shaded.ahc.org.asynchttpclient.ws.WebSocketUpgradeHandler; @AutoService(InstrumentationModule.class) -public class PlayWsInstrumentationModule extends InstrumentationModule { +public class PlayWsInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public PlayWsInstrumentationModule() { super("play-ws", "play-ws-2.0"); } @@ -37,20 +42,26 @@ public List typeInstrumentations() { new AbstractBootstrapInstrumentation()); } + @Override + public boolean isIndyReady() { + return true; + } + @SuppressWarnings("unused") public static class ClientAdvice { + @AssignReturned.ToArguments(@ToArgument(value = 1, index = 1)) @Advice.OnMethodEnter(suppress = Throwable.class) - public static void methodEnter( + public static Object[] methodEnter( @Advice.Argument(0) Request request, - @Advice.Argument(value = 1, readOnly = false) AsyncHandler asyncHandler, - @Advice.Local("otelContext") Context context) { + @Advice.Argument(1) AsyncHandler originalAsyncHandler) { + AsyncHandler asyncHandler = originalAsyncHandler; Context parentContext = currentContext(); if (!instrumenter().shouldStart(parentContext, request)) { - return; + return new Object[] {null, asyncHandler}; } - context = instrumenter().start(parentContext, request); + Context context = instrumenter().start(parentContext, request); if (asyncHandler instanceof StreamedAsyncHandler) { asyncHandler = @@ -60,13 +71,15 @@ public static void methodEnter( // websocket upgrade handlers aren't supported asyncHandler = new AsyncHandlerWrapper<>(asyncHandler, request, context, parentContext); } + return new Object[] {context, asyncHandler}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Argument(0) Request request, - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context) { + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter Object[] enterResult) { + Context context = (Context) enterResult[0]; if (context != null && throwable != null) { instrumenter().end(context, request, null, throwable); } diff --git a/instrumentation/play/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java b/instrumentation/play/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java index 590002e6b5a9..2aa2092eee81 100644 --- a/instrumentation/play/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java +++ b/instrumentation/play/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java @@ -13,18 +13,23 @@ import io.opentelemetry.context.Context; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import io.opentelemetry.javaagent.instrumentation.playws.AbstractBootstrapInstrumentation; import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation; import io.opentelemetry.javaagent.instrumentation.playws.HandlerPublisherInstrumentation; import java.util.List; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; +import net.bytebuddy.asm.Advice.AssignReturned; +import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument; import play.shaded.ahc.org.asynchttpclient.AsyncHandler; import play.shaded.ahc.org.asynchttpclient.Request; import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler; import play.shaded.ahc.org.asynchttpclient.ws.WebSocketUpgradeHandler; @AutoService(InstrumentationModule.class) -public class PlayWsInstrumentationModule extends InstrumentationModule { +public class PlayWsInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public PlayWsInstrumentationModule() { super("play-ws", "play-ws-2.1"); } @@ -37,20 +42,26 @@ public List typeInstrumentations() { new AbstractBootstrapInstrumentation()); } + @Override + public boolean isIndyReady() { + return true; + } + @SuppressWarnings("unused") public static class ClientAdvice { + @AssignReturned.ToArguments(@ToArgument(value = 1, index = 1)) @Advice.OnMethodEnter(suppress = Throwable.class) - public static void methodEnter( + public static Object[] methodEnter( @Advice.Argument(0) Request request, - @Advice.Argument(value = 1, readOnly = false) AsyncHandler asyncHandler, - @Advice.Local("otelContext") Context context) { + @Advice.Argument(1) AsyncHandler originalAsyncHandler) { + AsyncHandler asyncHandler = originalAsyncHandler; Context parentContext = currentContext(); if (!instrumenter().shouldStart(parentContext, request)) { - return; + return new Object[] {null, asyncHandler}; } - context = instrumenter().start(parentContext, request); + Context context = instrumenter().start(parentContext, request); if (asyncHandler instanceof StreamedAsyncHandler) { asyncHandler = @@ -60,13 +71,15 @@ public static void methodEnter( // websocket upgrade handlers aren't supported asyncHandler = new AsyncHandlerWrapper<>(asyncHandler, request, context, parentContext); } + return new Object[] {context, asyncHandler}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Argument(0) Request request, - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context) { + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter Object[] enterResult) { + Context context = (Context) enterResult[0]; if (context != null && throwable != null) { instrumenter().end(context, request, null, throwable); } diff --git a/instrumentation/play/play-ws/play-ws-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/HandlerPublisherInstrumentation.java b/instrumentation/play/play-ws/play-ws-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/HandlerPublisherInstrumentation.java index f72dd937fc8d..dbafbc849c92 100644 --- a/instrumentation/play/play-ws/play-ws-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/HandlerPublisherInstrumentation.java +++ b/instrumentation/play/play-ws/play-ws-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/HandlerPublisherInstrumentation.java @@ -11,6 +11,8 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; 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.matcher.ElementMatcher; import org.reactivestreams.Subscriber; @@ -31,10 +33,10 @@ public void transform(TypeTransformer transformer) { @SuppressWarnings("unused") public static class WrapSubscriberAdvice { + @AssignReturned.ToArguments(@ToArgument(0)) @Advice.OnMethodEnter(suppress = Throwable.class) - public static void enter( - @Advice.Argument(value = 0, readOnly = false) Subscriber subscriber) { - subscriber = new SubscriberWrapper<>(subscriber, Java8BytecodeBridge.currentContext()); + public static Subscriber enter(@Advice.Argument(0) Subscriber subscriber) { + return new SubscriberWrapper<>(subscriber, Java8BytecodeBridge.currentContext()); } } }