diff --git a/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchInstrumentationModule.java b/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchInstrumentationModule.java index 3397ae57ade4..d0be098bc245 100644 --- a/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchInstrumentationModule.java +++ b/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchInstrumentationModule.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 OpenSearchInstrumentationModule extends InstrumentationModule { +public class OpenSearchInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public OpenSearchInstrumentationModule() { super("opensearch-java", "opensearch-java-3.0", "opensearch"); } @@ -22,4 +24,9 @@ public OpenSearchInstrumentationModule() { public List typeInstrumentations() { return singletonList(new OpenSearchTransportInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchTransportInstrumentation.java b/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchTransportInstrumentation.java index 9a475aa76d92..6cf1cfe84993 100644 --- a/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchTransportInstrumentation.java +++ b/instrumentation/opensearch/opensearch-java-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opensearch/v3_0/OpenSearchTransportInstrumentation.java @@ -5,7 +5,6 @@ package io.opentelemetry.javaagent.instrumentation.opensearch.v3_0; -import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; import static io.opentelemetry.javaagent.instrumentation.opensearch.v3_0.OpenSearchSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isMethod; @@ -18,6 +17,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.concurrent.CompletableFuture; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -48,84 +48,90 @@ public void transform(TypeTransformer transformer) { this.getClass().getName() + "$PerformRequestAsyncAdvice"); } - @SuppressWarnings("unused") - public static class PerformRequestAdvice { + public static class AdviceScope { + private final OpenSearchRequest otelRequest; + private final Context context; + private final Scope scope; - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Object request, - @Advice.Argument(1) Endpoint endpoint, - @Advice.Local("otelRequest") OpenSearchRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { + private AdviceScope(OpenSearchRequest otelRequest, Context context, Scope scope) { + this.otelRequest = otelRequest; + this.context = context; + this.scope = scope; + } - Context parentContext = currentContext(); - otelRequest = + @Nullable + public static AdviceScope start(Object request, Endpoint endpoint) { + Context parentContext = Context.current(); + OpenSearchRequest otelRequest = OpenSearchRequest.create(endpoint.method(request), endpoint.requestUrl(request)); if (!instrumenter().shouldStart(parentContext, otelRequest)) { - return; + return null; } - - context = instrumenter().start(parentContext, otelRequest); - scope = context.makeCurrent(); + Context context = instrumenter().start(parentContext, otelRequest); + return new AdviceScope(otelRequest, context, context.makeCurrent()); } - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelRequest") OpenSearchRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { + public CompletableFuture wrapFuture(CompletableFuture future) { + return future.whenComplete(new OpenSearchResponseHandler(context, otelRequest)); + } - if (scope == null) { - return; - } + public void end(@Nullable Throwable throwable) { scope.close(); - instrumenter().end(context, otelRequest, null, throwable); } + + public void endAsync(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, otelRequest, null, throwable); + } + // span ended in OpenSearchResponseHandler + } } @SuppressWarnings("unused") - public static class PerformRequestAsyncAdvice { + public static class PerformRequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( + public static AdviceScope onEnter( @Advice.Argument(0) Object request, - @Advice.Argument(value = 1, readOnly = false) Endpoint endpoint, - @Advice.Local("otelRequest") OpenSearchRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - Context parentContext = currentContext(); - otelRequest = - OpenSearchRequest.create(endpoint.method(request), endpoint.requestUrl(request)); - if (!instrumenter().shouldStart(parentContext, otelRequest)) { - return; - } - - context = instrumenter().start(parentContext, otelRequest); - scope = context.makeCurrent(); + @Advice.Argument(1) Endpoint endpoint) { + return AdviceScope.start(request, endpoint); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Return(readOnly = false) CompletableFuture future, - @Advice.Local("otelRequest") OpenSearchRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - if (scope == null) { - return; + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter @Nullable AdviceScope adviceScope) { + if (adviceScope != null) { + adviceScope.end(throwable); } - scope.close(); + } + } - if (throwable != null) { - instrumenter().end(context, otelRequest, null, throwable); - } + @SuppressWarnings("unused") + public static class PerformRequestAsyncAdvice { - future.whenComplete(new OpenSearchResponseHandler(context, otelRequest)); + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Object[] onEnter( + @Advice.Argument(0) Object request, + @Advice.Argument(1) Endpoint endpoint) { + AdviceScope adviceScope = AdviceScope.start(request, endpoint); + return new Object[] {adviceScope}; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + @Advice.AssignReturned.ToReturned + public static CompletableFuture stopSpan( + @Advice.Return CompletableFuture future, + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter Object[] enterResult) { + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.endAsync(throwable); + return adviceScope.wrapFuture(future); + } + return future; } } }