diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java index 20f055e0b4ec..fbdf52bdf5a0 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java @@ -25,7 +25,9 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.Collection; import java.util.Map; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; +import net.bytebuddy.asm.Advice.AssignReturned; import net.bytebuddy.description.enumeration.EnumerationDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.implementation.bytecode.assign.Assigner; @@ -91,42 +93,60 @@ public void transform(TypeTransformer transformer) { @SuppressWarnings("unused") public static class MethodAdvice { + public static class AdviceScope { + private final MethodAndType classAndMethod; + private final Context context; + private final Scope scope; + + private AdviceScope(MethodAndType classAndMethod, Context context, Scope scope) { + this.classAndMethod = classAndMethod; + this.context = context; + this.scope = scope; + } + + @Nullable + public static AdviceScope start( + SpanKind spanKind, Class declaringClass, String methodName) { + Context parentContext = currentContext(); + MethodAndType methodAndType = + MethodAndType.create(ClassAndMethod.create(declaringClass, methodName), spanKind); + + if (!instrumenter().shouldStart(parentContext, methodAndType)) { + return null; + } + Context context = instrumenter().start(parentContext, methodAndType); + return new AdviceScope(methodAndType, context, context.makeCurrent()); + } + + public Object end( + Class methodReturnType, Object returnValue, @Nullable Throwable throwable) { + scope.close(); + return AsyncOperationEndSupport.create(instrumenter(), Void.class, methodReturnType) + .asyncEnd(context, classAndMethod, returnValue, throwable); + } + } + + @Nullable @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( + public static AdviceScope onEnter( @MethodSpanKind SpanKind spanKind, @Advice.Origin("#t") Class declaringClass, - @Advice.Origin("#m") String methodName, - @Advice.Local("otelMethod") MethodAndType classAndMethod, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - Context parentContext = currentContext(); - classAndMethod = - MethodAndType.create(ClassAndMethod.create(declaringClass, methodName), spanKind); - - if (!instrumenter().shouldStart(parentContext, classAndMethod)) { - return; - } - - context = instrumenter().start(parentContext, classAndMethod); - scope = context.makeCurrent(); + @Advice.Origin("#m") String methodName) { + return AdviceScope.start(spanKind, declaringClass, methodName); } + @AssignReturned.ToReturned @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( + public static Object stopSpan( @MethodReturnType Class methodReturnType, - @Advice.Local("otelMethod") MethodAndType classAndMethod, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Return(typing = Assigner.Typing.DYNAMIC, readOnly = false) Object returnValue, - @Advice.Thrown Throwable throwable) { - if (scope == null) { - return; - } - scope.close(); + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returnValue, + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter @Nullable AdviceScope adviceScope) { - returnValue = - AsyncOperationEndSupport.create(instrumenter(), Void.class, methodReturnType) - .asyncEnd(context, classAndMethod, returnValue, throwable); + if (adviceScope != null) { + return adviceScope.end(methodReturnType, returnValue, throwable); + } + return returnValue; } } } diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java index 3106c332c8da..71fe619da4db 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java @@ -15,6 +15,7 @@ import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; 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.tooling.config.MethodsConfigurationParser; import java.util.List; import java.util.Map; @@ -22,7 +23,8 @@ import java.util.stream.Collectors; @AutoService(InstrumentationModule.class) -public class MethodInstrumentationModule extends InstrumentationModule { +public class MethodInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { private static final String TRACE_METHODS_CONFIG = "otel.instrumentation.methods.include"; @@ -66,4 +68,9 @@ private static List parseConfigProperties() { public List typeInstrumentations() { return typeInstrumentations; } + + @Override + public boolean isIndyReady() { + return true; + } }