Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ public List<TypeInstrumentation> typeInstrumentations() {
return asList(
new RestClientTransportInstrumentation(), new RestClientHttpClientInstrumentation());
}

@Override
public boolean isIndyReady() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -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<Request, ElasticsearchEndpointDefinition> ENDPOINT_DEFINITION =
VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class);

private ElasticsearchApiClientSingletons() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -13,8 +14,6 @@

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;
Expand Down Expand Up @@ -72,8 +71,7 @@ public static void onExit(@Advice.Return Request request) {
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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -44,13 +43,11 @@ public static class RestClientTransportAdvice {
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onPrepareLowLevelRequest(
@Advice.Argument(1) Endpoint<?, ?, ?> endpoint, @Advice.Return Request request) {
VirtualField<Request, ElasticsearchEndpointDefinition> 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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 ElasticsearchRest5InstrumentationModule extends InstrumentationModule {
public class ElasticsearchRest5InstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public ElasticsearchRest5InstrumentationModule() {
super("elasticsearch-rest", "elasticsearch-rest-5.0", "elasticsearch");
}
Expand All @@ -22,4 +24,9 @@ public ElasticsearchRest5InstrumentationModule() {
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RestClientInstrumentation());
}

@Override
public boolean isIndyReady() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
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;
Expand All @@ -45,45 +48,67 @@ public void transform(TypeTransformer transformer) {
@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;

private AdviceScope(
ElasticsearchRestRequest request, Context parentContext, Context context, Scope scope) {
this.request = request;
this.parentContext = parentContext;
this.context = context;
this.scope = scope;
}

Context parentContext = currentContext();
request = ElasticsearchRestRequest.create(method, endpoint);
if (!instrumenter().shouldStart(parentContext, request)) {
return;
@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());
}

context = instrumenter().start(parentContext, request);
scope = context.makeCurrent();
public RestResponseListener wrapListener(ResponseListener listener) {
return new RestResponseListener(listener, parentContext, instrumenter(), context, request);
}

responseListener =
new RestResponseListener(
responseListener, 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
}
}

@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) {
@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;

if (scope == null) {
return;
ElasticsearchRestRequest request = ElasticsearchRestRequest.create(method, endpoint);
AdviceScope adviceScope = AdviceScope.start(request);
if (adviceScope == null) {
return new Object[] {null, responseListener};
}
scope.close();
responseListener = adviceScope.wrapListener(responseListener);
return new Object[] {adviceScope, responseListener};
}

if (throwable != null) {
instrumenter().end(context, request, null, throwable);
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Thrown Throwable throwable, @Advice.Enter Object[] enterResult) {
AdviceScope adviceScope = (AdviceScope) enterResult[0];
if (adviceScope != null) {
adviceScope.end(throwable);
}
// span ended in RestResponseListener
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,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 ElasticsearchRest6InstrumentationModule extends InstrumentationModule {
public class ElasticsearchRest6InstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
public ElasticsearchRest6InstrumentationModule() {
super("elasticsearch-rest", "elasticsearch-rest-6.4", "elasticsearch");
}
Expand All @@ -31,4 +33,9 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RestClientInstrumentation());
}

@Override
public boolean isIndyReady() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
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;
Expand All @@ -44,44 +47,67 @@ public void transform(TypeTransformer transformer) {
@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
}
}

@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) {
@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;

if (scope == null) {
return;
ElasticsearchRestRequest otelRequest =
ElasticsearchRestRequest.create(request.getMethod(), request.getEndpoint());
AdviceScope adviceScope = AdviceScope.start(otelRequest);
if (adviceScope == null) {
return new Object[] {null, responseListener};
}
scope.close();
responseListener = adviceScope.wrapListener(responseListener);
return new Object[] {adviceScope, responseListener};
}

if (throwable != null) {
instrumenter().end(context, otelRequest, null, throwable);
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Thrown @Nullable Throwable throwable, @Advice.Enter Object[] enterResult) {
AdviceScope adviceScope = (AdviceScope) enterResult[0];
if (adviceScope != null) {
adviceScope.end(throwable);
}
// span ended in RestResponseListener
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ public String getModuleGroup() {
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RestClientInstrumentation());
}

@Override
public boolean isIndyReady() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -20,5 +23,8 @@ public static Instrumenter<ElasticsearchRestRequest, Response> instrumenter() {
return INSTRUMENTER;
}

public static final VirtualField<Request, ElasticsearchEndpointDefinition> ENDPOINT_DEFINITION =
VirtualField.find(Request.class, ElasticsearchEndpointDefinition.class);

private ElasticsearchRest7Singletons() {}
}
Loading