From 75a342995cfeccd3afdbfe1809d05880f8c08f36 Mon Sep 17 00:00:00 2001 From: SylvainJuge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 18 Sep 2025 14:30:48 +0200 Subject: [PATCH] make elasticsearch indy-ready (#14672) --- ...csearchApiClientInstrumentationModule.java | 5 + .../ElasticsearchApiClientSingletons.java | 18 +++ .../RestClientHttpClientInstrumentation.java | 6 +- .../RestClientTransportInstrumentation.java | 7 +- ...asticsearchRest5InstrumentationModule.java | 9 +- .../rest/v5_0/RestClientInstrumentation.java | 85 +++++++---- ...asticsearchRest6InstrumentationModule.java | 9 +- .../rest/v6_4/RestClientInstrumentation.java | 84 +++++++---- ...asticsearchRest7InstrumentationModule.java | 5 + .../v7_0/ElasticsearchRest7Singletons.java | 6 + .../rest/v7_0/RestClientInstrumentation.java | 136 +++++++++--------- .../v5_0/AbstractClientInstrumentation.java | 87 +++++++---- ...5TransportClientInstrumentationModule.java | 9 +- .../v5_3/AbstractClientInstrumentation.java | 87 +++++++---- ...3TransportClientInstrumentationModule.java | 9 +- .../v6_0/AbstractClientInstrumentation.java | 87 +++++++---- ...6TransportClientInstrumentationModule.java | 9 +- 17 files changed, 431 insertions(+), 227 deletions(-) create mode 100644 instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientSingletons.java diff --git a/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientInstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientInstrumentationModule.java index 75cad4dee6..860895ec7a 100644 --- a/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientInstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientInstrumentationModule.java @@ -42,4 +42,9 @@ public class ElasticsearchApiClientInstrumentationModule extends Instrumentation return asList( new RestClientTransportInstrumentation(), new RestClientHttpClientInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientSingletons.java b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientSingletons.java new file mode 100644 index 0000000000..abc4acca17 --- /dev/null +++ b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/ElasticsearchApiClientSingletons.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient; + +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.ElasticsearchEndpointDefinition; +import org.elasticsearch.client.Request; + +public class ElasticsearchApiClientSingletons { + + public static final VirtualField ENDPOINT_DEFINITION = + VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class); + + private ElasticsearchApiClientSingletons() {} +} diff --git a/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientHttpClientInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientHttpClientInstrumentation.java index f4fe0e2780..8851e1dbfd 100644 --- a/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientHttpClientInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientHttpClientInstrumentation.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient; +import static io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient.ElasticsearchApiClientSingletons.ENDPOINT_DEFINITION; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; @@ -13,8 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.util.VirtualField; -import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.ElasticsearchEndpointDefinition; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import net.bytebuddy.asm.Advice; @@ -72,8 +71,7 @@ public class RestClientHttpClientInstrumentation implements TypeInstrumentation if (endpointId.startsWith("es/") && endpointId.length() > 3) { endpointId = endpointId.substring(3); } - VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class) - .set(request, ElasticsearchEndpointMap.get(endpointId)); + ENDPOINT_DEFINITION.set(request, ElasticsearchEndpointMap.get(endpointId)); } } } diff --git a/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientTransportInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientTransportInstrumentation.java index e11d142dd1..c77ca49c34 100644 --- a/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientTransportInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-api-client-7.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/apiclient/RestClientTransportInstrumentation.java @@ -5,14 +5,13 @@ package io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient; +import static io.opentelemetry.javaagent.instrumentation.elasticsearch.apiclient.ElasticsearchApiClientSingletons.ENDPOINT_DEFINITION; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import co.elastic.clients.transport.Endpoint; -import io.opentelemetry.instrumentation.api.util.VirtualField; -import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.ElasticsearchEndpointDefinition; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import net.bytebuddy.asm.Advice; @@ -44,13 +43,11 @@ public class RestClientTransportInstrumentation implements TypeInstrumentation { @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void onPrepareLowLevelRequest( @Advice.Argument(1) Endpoint endpoint, @Advice.Return Request request) { - VirtualField virtualField = - VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class); String endpointId = endpoint.id(); if (endpointId.startsWith("es/") && endpointId.length() > 3) { endpointId = endpointId.substring(3); } - virtualField.set(request, ElasticsearchEndpointMap.get(endpointId)); + ENDPOINT_DEFINITION.set(request, ElasticsearchEndpointMap.get(endpointId)); } } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5InstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5InstrumentationModule.java index c5c4a58252..37cf332840 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5InstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/ElasticsearchRest5InstrumentationModule.java @@ -10,10 +10,12 @@ import static java.util.Collections.singletonList; 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 ElasticsearchRest5InstrumentationModule extends InstrumentationModule { +public class ElasticsearchRest5InstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public ElasticsearchRest5InstrumentationModule() { super("elasticsearch-rest", "elasticsearch-rest-5.0", "elasticsearch"); } @@ -22,4 +24,9 @@ public class ElasticsearchRest5InstrumentationModule extends InstrumentationModu public List typeInstrumentations() { return singletonList(new RestClientInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/RestClientInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/RestClientInstrumentation.java index 57585f2a8c..41055b1e60 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/RestClientInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/RestClientInstrumentation.java @@ -19,7 +19,10 @@ import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal. import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.RestResponseListener; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; 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.elasticsearch.client.ResponseListener; @@ -45,45 +48,67 @@ public class RestClientInstrumentation implements TypeInstrumentation { @SuppressWarnings("unused") public static class PerformRequestAsyncAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) String method, - @Advice.Argument(1) String endpoint, - @Advice.Local("otelRequest") ElasticsearchRestRequest request, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Argument(value = 5, readOnly = false) ResponseListener responseListener) { + public static class AdviceScope { + private final ElasticsearchRestRequest request; + private final Context parentContext; + private final Context context; + private final Scope scope; - Context parentContext = currentContext(); - request = ElasticsearchRestRequest.create(method, endpoint); - if (!instrumenter().shouldStart(parentContext, request)) { - return; + private AdviceScope( + ElasticsearchRestRequest request, Context parentContext, Context context, Scope scope) { + this.request = request; + this.parentContext = parentContext; + this.context = context; + this.scope = scope; } - context = instrumenter().start(parentContext, request); - scope = context.makeCurrent(); + @Nullable + public static AdviceScope start(ElasticsearchRestRequest request) { + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return null; + } + Context context = instrumenter().start(parentContext, request); + return new AdviceScope(request, parentContext, context, context.makeCurrent()); + } - responseListener = - new RestResponseListener( - responseListener, parentContext, instrumenter(), context, request); + public RestResponseListener wrapListener(ResponseListener listener) { + return new RestResponseListener(listener, parentContext, instrumenter(), context, request); + } + + public void end(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } + // span ended in RestResponseListener + } + } + + @AssignReturned.ToArguments(@ToArgument(value = 5, index = 1)) + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Object[] onEnter( + @Advice.Argument(0) String method, + @Advice.Argument(1) String endpoint, + @Advice.Argument(5) ResponseListener originalResponseListener) { + ResponseListener responseListener = originalResponseListener; + + ElasticsearchRestRequest request = ElasticsearchRestRequest.create(method, endpoint); + AdviceScope adviceScope = AdviceScope.start(request); + if (adviceScope == null) { + return new Object[] {null, responseListener}; + } + responseListener = adviceScope.wrapListener(responseListener); + return new Object[] {adviceScope, responseListener}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelRequest") ElasticsearchRestRequest request, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - if (scope == null) { - return; + @Advice.Thrown Throwable throwable, @Advice.Enter Object[] enterResult) { + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.end(throwable); } - scope.close(); - - if (throwable != null) { - instrumenter().end(context, request, null, throwable); - } - // span ended in RestResponseListener } } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6InstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6InstrumentationModule.java index efa09e2654..f9b5701abd 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6InstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/ElasticsearchRest6InstrumentationModule.java @@ -12,11 +12,13 @@ import static net.bytebuddy.matcher.ElementMatchers.not; 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 ElasticsearchRest6InstrumentationModule extends InstrumentationModule { +public class ElasticsearchRest6InstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public ElasticsearchRest6InstrumentationModule() { super("elasticsearch-rest", "elasticsearch-rest-6.4", "elasticsearch"); } @@ -31,4 +33,9 @@ public class ElasticsearchRest6InstrumentationModule extends InstrumentationModu public List typeInstrumentations() { return singletonList(new RestClientInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/RestClientInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/RestClientInstrumentation.java index 60c0ac9b2e..d489fba30a 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/RestClientInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/RestClientInstrumentation.java @@ -18,7 +18,10 @@ import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal. import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.RestResponseListener; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; 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.elasticsearch.client.Request; @@ -44,44 +47,67 @@ public class RestClientInstrumentation implements TypeInstrumentation { @SuppressWarnings("unused") public static class PerformRequestAsyncAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Request request, - @Advice.Argument(value = 1, readOnly = false) ResponseListener responseListener, - @Advice.Local("otelRequest") ElasticsearchRestRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { + public static class AdviceScope { + private final ElasticsearchRestRequest request; + private final Context parentContext; + private final Context context; + private final Scope scope; - Context parentContext = currentContext(); - otelRequest = ElasticsearchRestRequest.create(request.getMethod(), request.getEndpoint()); - if (!instrumenter().shouldStart(parentContext, otelRequest)) { - return; + private AdviceScope( + ElasticsearchRestRequest request, Context parentContext, Context context, Scope scope) { + this.request = request; + this.parentContext = parentContext; + this.context = context; + this.scope = scope; } - context = instrumenter().start(parentContext, otelRequest); - scope = context.makeCurrent(); + @Nullable + public static AdviceScope start(ElasticsearchRestRequest request) { + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return null; + } + Context context = instrumenter().start(parentContext, request); + return new AdviceScope(request, parentContext, context, context.makeCurrent()); + } - responseListener = - new RestResponseListener( - responseListener, parentContext, instrumenter(), context, otelRequest); + public RestResponseListener wrapListener(ResponseListener listener) { + return new RestResponseListener(listener, parentContext, instrumenter(), context, request); + } + + public void end(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } + // span ended in RestResponseListener + } + } + + @AssignReturned.ToArguments(@ToArgument(value = 1, index = 1)) + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Object[] onEnter( + @Advice.Argument(0) Request request, + @Advice.Argument(1) ResponseListener originalResponseListener) { + ResponseListener responseListener = originalResponseListener; + + ElasticsearchRestRequest otelRequest = + ElasticsearchRestRequest.create(request.getMethod(), request.getEndpoint()); + AdviceScope adviceScope = AdviceScope.start(otelRequest); + if (adviceScope == null) { + return new Object[] {null, responseListener}; + } + responseListener = adviceScope.wrapListener(responseListener); + return new Object[] {adviceScope, responseListener}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelRequest") ElasticsearchRestRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - if (scope == null) { - return; + @Advice.Thrown @Nullable Throwable throwable, @Advice.Enter Object[] enterResult) { + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.end(throwable); } - scope.close(); - - if (throwable != null) { - instrumenter().end(context, otelRequest, null, throwable); - } - // span ended in RestResponseListener } } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7InstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7InstrumentationModule.java index 22d00be64d..bb4dd49432 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7InstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7InstrumentationModule.java @@ -43,4 +43,9 @@ public class ElasticsearchRest7InstrumentationModule extends InstrumentationModu public List typeInstrumentations() { return singletonList(new RestClientInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Singletons.java b/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Singletons.java index 7b36647f2c..9783ba4dea 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Singletons.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/ElasticsearchRest7Singletons.java @@ -6,8 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.ElasticsearchEndpointDefinition; import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.ElasticsearchRestRequest; import io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.ElasticsearchRestJavaagentInstrumenterFactory; +import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; public final class ElasticsearchRest7Singletons { @@ -20,5 +23,8 @@ public final class ElasticsearchRest7Singletons { return INSTRUMENTER; } + public static final VirtualField ENDPOINT_DEFINITION = + VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class); + private ElasticsearchRest7Singletons() {} } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/RestClientInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/RestClientInstrumentation.java index 8dc0dba7f9..ca25f7a2af 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/RestClientInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v7_0/RestClientInstrumentation.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0; import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0.ElasticsearchRest7Singletons.ENDPOINT_DEFINITION; import static io.opentelemetry.javaagent.instrumentation.elasticsearch.rest.v7_0.ElasticsearchRest7Singletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -14,13 +15,14 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.util.VirtualField; -import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.ElasticsearchEndpointDefinition; import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.ElasticsearchRestRequest; import io.opentelemetry.instrumentation.elasticsearch.rest.common.v5_0.internal.RestResponseListener; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.annotation.Nullable; 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.elasticsearch.client.Request; @@ -50,101 +52,107 @@ public class RestClientInstrumentation implements TypeInstrumentation { this.getClass().getName() + "$PerformRequestAsyncAdvice"); } + public static class AdviceScope { + private final ElasticsearchRestRequest request; + private final Context context; + private final Context parentContext; + private final Scope scope; + + private AdviceScope( + ElasticsearchRestRequest request, Context parentContext, Context context, Scope scope) { + this.request = request; + this.parentContext = parentContext; + this.context = context; + this.scope = scope; + } + + @Nullable + public static AdviceScope start(ElasticsearchRestRequest request) { + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return null; + } + Context context = instrumenter().start(parentContext, request); + return new AdviceScope(request, parentContext, context, context.makeCurrent()); + } + + public ResponseListener wrapListener(ResponseListener responseListener) { + return new RestResponseListener( + responseListener, parentContext, instrumenter(), context, request); + } + + public void endWithListener(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } + // span ended in RestResponseListener + } + + public void endWithResponse(@Nullable Throwable throwable, @Nullable Response response) { + scope.close(); + instrumenter().end(context, request, response, throwable); + } + } + @SuppressWarnings("unused") public static class PerformRequestAdvice { + @Nullable @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Request request, - @Advice.Local("otelRequest") ElasticsearchRestRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - Context parentContext = currentContext(); - VirtualField virtualField = - VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class); - otelRequest = + public static AdviceScope onEnter(@Advice.Argument(0) Request request) { + ElasticsearchRestRequest otelRequest = ElasticsearchRestRequest.create( request.getMethod(), request.getEndpoint(), // set by elasticsearch-api-client instrumentation - virtualField.get(request), + ENDPOINT_DEFINITION.get(request), request.getEntity()); - if (!instrumenter().shouldStart(parentContext, otelRequest)) { - return; - } - - context = instrumenter().start(parentContext, otelRequest); - scope = context.makeCurrent(); + return AdviceScope.start(otelRequest); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Return Response response, - @Advice.Thrown Throwable throwable, - @Advice.Local("otelRequest") ElasticsearchRestRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - if (scope == null) { - return; + @Advice.Return @Nullable Response response, + @Advice.Thrown @Nullable Throwable throwable, + @Advice.Enter @Nullable AdviceScope adviceScope) { + if (adviceScope != null) { + adviceScope.endWithResponse(throwable, response); } - scope.close(); - - instrumenter().end(context, otelRequest, response, throwable); } } @SuppressWarnings("unused") public static class PerformRequestAsyncAdvice { + @AssignReturned.ToArguments(@ToArgument(value = 1, index = 1)) @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( + public static Object[] onEnter( @Advice.Argument(0) Request request, - @Advice.Argument(value = 1, readOnly = false) ResponseListener responseListener, - @Advice.Local("otelRequest") ElasticsearchRestRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - Context parentContext = currentContext(); - VirtualField virtualField = - VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class); - - otelRequest = + @Advice.Argument(1) ResponseListener originalResponseListener) { + ResponseListener responseListener = originalResponseListener; + ElasticsearchRestRequest otelRequest = ElasticsearchRestRequest.create( request.getMethod(), request.getEndpoint(), // set by elasticsearch-api-client instrumentation - virtualField.get(request), + ENDPOINT_DEFINITION.get(request), request.getEntity()); - if (!instrumenter().shouldStart(parentContext, otelRequest)) { - return; + AdviceScope adviceScope = AdviceScope.start(otelRequest); + if (adviceScope == null) { + return new Object[] {null, responseListener}; } - - context = instrumenter().start(parentContext, otelRequest); - scope = context.makeCurrent(); - - responseListener = - new RestResponseListener( - responseListener, parentContext, instrumenter(), context, otelRequest); + responseListener = adviceScope.wrapListener(responseListener); + return new Object[] {adviceScope, responseListener}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelRequest") ElasticsearchRestRequest otelRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - if (scope == null) { - return; + @Advice.Thrown @Nullable Throwable throwable, @Advice.Enter Object[] enterResult) { + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.endWithListener(throwable); } - scope.close(); - - if (throwable != null) { - instrumenter().end(context, otelRequest, null, throwable); - } - // span ended in RestResponseListener } } } diff --git a/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/AbstractClientInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/AbstractClientInstrumentation.java index 9cedbfe669..971ac12d87 100644 --- a/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/AbstractClientInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/AbstractClientInstrumentation.java @@ -17,7 +17,10 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.instrumentation.elasticsearch.transport.ElasticTransportRequest; import io.opentelemetry.javaagent.instrumentation.elasticsearch.transport.TransportActionListener; +import javax.annotation.Nullable; 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.elasticsearch.action.Action; @@ -47,44 +50,68 @@ public class AbstractClientInstrumentation implements TypeInstrumentation { @SuppressWarnings("unused") public static class ExecuteAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Action action, - @Advice.Argument(1) ActionRequest actionRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelRequest") ElasticTransportRequest transportRequest, - @Advice.Argument(value = 2, readOnly = false) - ActionListener actionListener) { + public static class AdviceScope { + private final ElasticTransportRequest request; + private final Context parentContext; + private final Context context; + private final Scope scope; - transportRequest = ElasticTransportRequest.create(action, actionRequest); - Context parentContext = currentContext(); - if (!instrumenter().shouldStart(parentContext, transportRequest)) { - return; + private AdviceScope( + ElasticTransportRequest request, Context parentContext, Context context, Scope scope) { + this.request = request; + this.parentContext = parentContext; + this.context = context; + this.scope = scope; } - context = instrumenter().start(parentContext, transportRequest); - scope = context.makeCurrent(); + @Nullable + public static AdviceScope start(ElasticTransportRequest request) { + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return null; + } + Context context = instrumenter().start(parentContext, request); + return new AdviceScope(request, parentContext, context, context.makeCurrent()); + } - actionListener = - new TransportActionListener<>( - instrumenter(), transportRequest, actionListener, context, parentContext); + public ActionListener wrapListener( + ActionListener actionListener) { + return new TransportActionListener<>( + instrumenter(), request, actionListener, context, parentContext); + } + + public void end(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } + } + } + + @AssignReturned.ToArguments(@ToArgument(value = 2, index = 1)) + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Object[] onEnter( + @Advice.Argument(0) Action action, + @Advice.Argument(1) ActionRequest actionRequest, + @Advice.Argument(2) ActionListener originalActionListener) { + ActionListener actionListener = originalActionListener; + + ElasticTransportRequest request = ElasticTransportRequest.create(action, actionRequest); + AdviceScope adviceScope = AdviceScope.start(request); + if (adviceScope == null) { + return new Object[] {null, actionListener}; + } + + actionListener = adviceScope.wrapListener(actionListener); + return new Object[] {adviceScope, actionListener}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelRequest") ElasticTransportRequest transportRequest) { - if (scope == null) { - return; - } - - scope.close(); - - if (throwable != null) { - instrumenter().end(context, transportRequest, null, throwable); + @Advice.Thrown @Nullable Throwable throwable, @Advice.Enter Object[] enterResult) { + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.end(throwable); } } } diff --git a/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/Elasticsearch5TransportClientInstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/Elasticsearch5TransportClientInstrumentationModule.java index 0aed966de2..016283cf36 100644 --- a/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/Elasticsearch5TransportClientInstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_0/Elasticsearch5TransportClientInstrumentationModule.java @@ -10,10 +10,12 @@ import static java.util.Collections.singletonList; 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 Elasticsearch5TransportClientInstrumentationModule extends InstrumentationModule { +public class Elasticsearch5TransportClientInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public Elasticsearch5TransportClientInstrumentationModule() { super("elasticsearch-transport", "elasticsearch-transport-5.0", "elasticsearch"); } @@ -22,4 +24,9 @@ public class Elasticsearch5TransportClientInstrumentationModule extends Instrume public List typeInstrumentations() { return singletonList(new AbstractClientInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/AbstractClientInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/AbstractClientInstrumentation.java index 6e1405d582..2d8bfe7fed 100644 --- a/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/AbstractClientInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/AbstractClientInstrumentation.java @@ -17,7 +17,10 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.instrumentation.elasticsearch.transport.ElasticTransportRequest; import io.opentelemetry.javaagent.instrumentation.elasticsearch.transport.TransportActionListener; +import javax.annotation.Nullable; 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.elasticsearch.action.Action; @@ -47,44 +50,68 @@ public class AbstractClientInstrumentation implements TypeInstrumentation { @SuppressWarnings("unused") public static class ExecuteAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Action action, - @Advice.Argument(1) ActionRequest actionRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelRequest") ElasticTransportRequest transportRequest, - @Advice.Argument(value = 2, readOnly = false) - ActionListener actionListener) { + public static class AdviceScope { + private final ElasticTransportRequest request; + private final Context parentContext; + private final Context context; + private final Scope scope; - transportRequest = ElasticTransportRequest.create(action, actionRequest); - Context parentContext = currentContext(); - if (!instrumenter().shouldStart(parentContext, transportRequest)) { - return; + private AdviceScope( + ElasticTransportRequest request, Context parentContext, Context context, Scope scope) { + this.request = request; + this.parentContext = parentContext; + this.context = context; + this.scope = scope; } - context = instrumenter().start(parentContext, transportRequest); - scope = context.makeCurrent(); + @Nullable + public static AdviceScope start(ElasticTransportRequest request) { + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return null; + } + Context context = instrumenter().start(parentContext, request); + return new AdviceScope(request, parentContext, context, context.makeCurrent()); + } - actionListener = - new TransportActionListener<>( - instrumenter(), transportRequest, actionListener, context, parentContext); + public ActionListener wrapListener( + ActionListener actionListener) { + return new TransportActionListener<>( + instrumenter(), request, actionListener, context, parentContext); + } + + public void end(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } + } + } + + @AssignReturned.ToArguments(@ToArgument(value = 2, index = 1)) + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Object[] onEnter( + @Advice.Argument(0) Action action, + @Advice.Argument(1) ActionRequest actionRequest, + @Advice.Argument(2) ActionListener originalActionListener) { + ActionListener actionListener = originalActionListener; + + ElasticTransportRequest request = ElasticTransportRequest.create(action, actionRequest); + AdviceScope adviceScope = AdviceScope.start(request); + if (adviceScope == null) { + return new Object[] {null, actionListener}; + } + + actionListener = adviceScope.wrapListener(actionListener); + return new Object[] {adviceScope, actionListener}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelRequest") ElasticTransportRequest transportRequest) { - if (scope == null) { - return; - } - - scope.close(); - - if (throwable != null) { - instrumenter().end(context, transportRequest, null, throwable); + @Advice.Thrown @Nullable Throwable throwable, @Advice.Enter Object[] enterResult) { + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.end(throwable); } } } diff --git a/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/Elasticsearch53TransportClientInstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/Elasticsearch53TransportClientInstrumentationModule.java index eda768845b..dc5d5e6a60 100644 --- a/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/Elasticsearch53TransportClientInstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v5_3/Elasticsearch53TransportClientInstrumentationModule.java @@ -10,11 +10,13 @@ import static java.util.Collections.singletonList; 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; /** Beginning in version 5.3.0, DocumentRequest was renamed to DocWriteRequest. */ @AutoService(InstrumentationModule.class) -public class Elasticsearch53TransportClientInstrumentationModule extends InstrumentationModule { +public class Elasticsearch53TransportClientInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public Elasticsearch53TransportClientInstrumentationModule() { super("elasticsearch-transport", "elasticsearch-transport-5.3", "elasticsearch"); } @@ -23,4 +25,9 @@ public class Elasticsearch53TransportClientInstrumentationModule extends Instrum public List typeInstrumentations() { return singletonList(new AbstractClientInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } } diff --git a/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/AbstractClientInstrumentation.java b/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/AbstractClientInstrumentation.java index f4c27bba78..c95ee9c462 100644 --- a/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/AbstractClientInstrumentation.java +++ b/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/AbstractClientInstrumentation.java @@ -18,7 +18,10 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.instrumentation.elasticsearch.transport.ElasticTransportRequest; import io.opentelemetry.javaagent.instrumentation.elasticsearch.transport.TransportActionListener; +import javax.annotation.Nullable; 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.elasticsearch.action.ActionListener; @@ -51,44 +54,68 @@ public class AbstractClientInstrumentation implements TypeInstrumentation { @SuppressWarnings("unused") public static class ExecuteAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Object action, - @Advice.Argument(1) ActionRequest actionRequest, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelRequest") ElasticTransportRequest transportRequest, - @Advice.Argument(value = 2, readOnly = false) - ActionListener actionListener) { + public static class AdviceScope { + private final ElasticTransportRequest request; + private final Context parentContext; + private final Context context; + private final Scope scope; - transportRequest = ElasticTransportRequest.create(action, actionRequest); - Context parentContext = currentContext(); - if (!instrumenter().shouldStart(parentContext, transportRequest)) { - return; + private AdviceScope( + ElasticTransportRequest request, Context parentContext, Context context, Scope scope) { + this.request = request; + this.parentContext = parentContext; + this.context = context; + this.scope = scope; } - context = instrumenter().start(parentContext, transportRequest); - scope = context.makeCurrent(); + @Nullable + public static AdviceScope start(ElasticTransportRequest request) { + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return null; + } + Context context = instrumenter().start(parentContext, request); + return new AdviceScope(request, parentContext, context, context.makeCurrent()); + } - actionListener = - new TransportActionListener<>( - instrumenter(), transportRequest, actionListener, context, parentContext); + public ActionListener wrapListener( + ActionListener actionListener) { + return new TransportActionListener<>( + instrumenter(), request, actionListener, context, parentContext); + } + + public void end(@Nullable Throwable throwable) { + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } + } + } + + @AssignReturned.ToArguments(@ToArgument(value = 2, index = 1)) + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Object[] onEnter( + @Advice.Argument(0) Object action, + @Advice.Argument(1) ActionRequest actionRequest, + @Advice.Argument(2) ActionListener originalActionListener) { + ActionListener actionListener = originalActionListener; + + ElasticTransportRequest request = ElasticTransportRequest.create(action, actionRequest); + AdviceScope adviceScope = AdviceScope.start(request); + if (adviceScope == null) { + return new Object[] {null, actionListener}; + } + + actionListener = adviceScope.wrapListener(actionListener); + return new Object[] {adviceScope, actionListener}; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelRequest") ElasticTransportRequest transportRequest) { - if (scope == null) { - return; - } - - scope.close(); - - if (throwable != null) { - instrumenter().end(context, transportRequest, null, throwable); + @Advice.Thrown @Nullable Throwable throwable, @Advice.Enter Object[] enterResult) { + AdviceScope adviceScope = (AdviceScope) enterResult[0]; + if (adviceScope != null) { + adviceScope.end(throwable); } } } diff --git a/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/Elasticsearch6TransportClientInstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/Elasticsearch6TransportClientInstrumentationModule.java index f888bc2815..d53efeb125 100644 --- a/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/Elasticsearch6TransportClientInstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/transport/v6_0/Elasticsearch6TransportClientInstrumentationModule.java @@ -10,6 +10,7 @@ import static java.util.Collections.singletonList; 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; /** @@ -17,7 +18,8 @@ import java.util.List; * an abstract class, so the bytecode isn't directly compatible. */ @AutoService(InstrumentationModule.class) -public class Elasticsearch6TransportClientInstrumentationModule extends InstrumentationModule { +public class Elasticsearch6TransportClientInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { public Elasticsearch6TransportClientInstrumentationModule() { super("elasticsearch-transport", "elasticsearch-transport-6.0", "elasticsearch"); } @@ -26,4 +28,9 @@ public class Elasticsearch6TransportClientInstrumentationModule extends Instrume public List typeInstrumentations() { return singletonList(new AbstractClientInstrumentation()); } + + @Override + public boolean isIndyReady() { + return true; + } }