Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.opentelemetry.context.Scope;
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.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
Expand Down Expand Up @@ -47,32 +48,46 @@ public void transform(TypeTransformer transformer) {
@SuppressWarnings("unused")
public static class ExecuteMethodAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(
@Advice.Argument(1) HttpMethod httpMethod,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext();
if (!instrumenter().shouldStart(parentContext, httpMethod)) {
return;
public static class AdviceScope {
private final Context context;
private final Scope scope;
private final HttpMethod httpMethod;

private AdviceScope(Context context, Scope scope, HttpMethod httpMethod) {
this.context = context;
this.scope = scope;
this.httpMethod = httpMethod;
}

@Nullable
public static AdviceScope start(HttpMethod httpMethod) {
Context parentContext = currentContext();
if (!instrumenter().shouldStart(parentContext, httpMethod)) {
return null;
}
Context context = instrumenter().start(parentContext, httpMethod);
return new AdviceScope(context, context.makeCurrent(), httpMethod);
}

public void end(Throwable throwable) {
scope.close();
instrumenter().end(context, httpMethod, httpMethod, throwable);
}
}

context = instrumenter().start(parentContext, httpMethod);
scope = context.makeCurrent();
@Advice.OnMethodEnter(suppress = Throwable.class)
public static AdviceScope methodEnter(@Advice.Argument(1) HttpMethod httpMethod) {
return AdviceScope.start(httpMethod);
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Argument(1) HttpMethod httpMethod,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
@Advice.Thrown @Nullable Throwable throwable,
@Advice.Enter @Nullable AdviceScope adviceScope) {

scope.close();
instrumenter().end(context, httpMethod, httpMethod, throwable);
if (adviceScope != null) {
adviceScope.end(throwable);
}
}
}
}
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 ApacheHttpClientInstrumentationModule extends InstrumentationModule {
public class ApacheHttpClientInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {

public ApacheHttpClientInstrumentationModule() {
super("apache-httpclient", "apache-httpclient-2.0");
Expand All @@ -23,4 +25,9 @@ public ApacheHttpClientInstrumentationModule() {
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new ApacheHttpClientInstrumentation());
}

@Override
public boolean isIndyReady() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import io.opentelemetry.context.Scope;
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.apache.http.HttpHost;
Expand Down Expand Up @@ -123,171 +126,140 @@ public void transform(TypeTransformer transformer) {
this.getClass().getName() + "$RequestWithHandlerAdvice");
}

@SuppressWarnings("unused")
public static class UriRequestAdvice {
public static class AdviceScope {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[for reviewer] this AdviceScope class has been moved outside of the Advice classes as it allows to remove duplication, otherwise by default almost identical AdviceScope inner classes are created for each advice class.

private final ApacheHttpClientRequest otelRequest;
private final Context parentContext;
private final Context context;
private final Scope scope;

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

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(
@Advice.Argument(0) HttpUriRequest request,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
@Nullable
public static AdviceScope start(ApacheHttpClientRequest otelRequest) {
Context parentContext = currentContext();

otelRequest = new ApacheHttpClientRequest(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, parentContext, context, context.makeCurrent());
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Argument(0) HttpUriRequest request,
@Advice.Return Object result,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
public <T> ResponseHandler<T> wrapHandler(ResponseHandler<T> handler) {
return new WrappingStatusSettingResponseHandler<>(
context, parentContext, otelRequest, handler);
}

public void end(@Nullable Object result, @Nullable Throwable throwable) {
scope.close();
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
}
}

@SuppressWarnings("unused")
public static class UriRequestWithHandlerAdvice {
public static class UriRequestAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(
@Advice.Argument(0) HttpUriRequest request,
@Advice.Argument(value = 1, readOnly = false) ResponseHandler<?> handler,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext();
public static AdviceScope methodEnter(@Advice.Argument(0) HttpUriRequest request) {
return AdviceScope.start(new ApacheHttpClientRequest(request));
}

otelRequest = new ApacheHttpClientRequest(request);
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Argument(0) HttpUriRequest request,
@Advice.Return @Nullable Object result,
@Advice.Thrown @Nullable Throwable throwable,
@Advice.Enter @Nullable AdviceScope adviceScope) {

if (!instrumenter().shouldStart(parentContext, otelRequest)) {
return;
if (adviceScope != null) {
adviceScope.end(result, throwable);
}
}
}

context = instrumenter().start(parentContext, otelRequest);
scope = context.makeCurrent();
@SuppressWarnings("unused")
public static class UriRequestWithHandlerAdvice {

@AssignReturned.ToArguments(@ToArgument(value = 1, index = 1))
@Advice.OnMethodEnter(suppress = Throwable.class)
public static Object[] methodEnter(
@Advice.Argument(0) HttpUriRequest request,
@Advice.Argument(1) ResponseHandler<?> handler) {

AdviceScope adviceScope = AdviceScope.start(new ApacheHttpClientRequest(request));
// Wrap the handler so we capture the status code
if (handler != null) {
handler =
new WrappingStatusSettingResponseHandler<>(
context, parentContext, otelRequest, handler);
}
return new Object[] {
adviceScope, adviceScope == null ? handler : adviceScope.wrapHandler(handler)
};
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Argument(0) HttpUriRequest request,
@Advice.Return Object result,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
@Advice.Enter Object[] enterResult) {

scope.close();
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
AdviceScope adviceScope = (AdviceScope) enterResult[0];
if (adviceScope != null) {
adviceScope.end(result, throwable);
}
}
}

@SuppressWarnings("unused")
public static class RequestAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(
@Advice.Argument(0) HttpHost host,
@Advice.Argument(1) HttpRequest request,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext();

otelRequest = new ApacheHttpClientRequest(host, request);

if (!instrumenter().shouldStart(parentContext, otelRequest)) {
return;
}

context = instrumenter().start(parentContext, otelRequest);
scope = context.makeCurrent();
public static AdviceScope methodEnter(
@Advice.Argument(0) HttpHost host, @Advice.Argument(1) HttpRequest request) {
return AdviceScope.start(new ApacheHttpClientRequest(host, request));
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Return Object result,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
@Advice.Enter AdviceScope adviceScope) {

scope.close();
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
if (adviceScope != null) {
adviceScope.end(result, throwable);
}
}
}

@SuppressWarnings("unused")
public static class RequestWithHandlerAdvice {

@AssignReturned.ToArguments(@ToArgument(value = 2, index = 1))
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(
public static Object[] methodEnter(
@Advice.Argument(0) HttpHost host,
@Advice.Argument(1) HttpRequest request,
@Advice.Argument(value = 2, readOnly = false) ResponseHandler<?> handler,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext();

otelRequest = new ApacheHttpClientRequest(host, request);

if (!instrumenter().shouldStart(parentContext, otelRequest)) {
return;
}

context = instrumenter().start(parentContext, otelRequest);
scope = context.makeCurrent();

// Wrap the handler so we capture the status code
if (handler != null) {
handler =
new WrappingStatusSettingResponseHandler<>(
context, parentContext, otelRequest, handler);
}
@Advice.Argument(2) ResponseHandler<?> handler) {

AdviceScope adviceScope = AdviceScope.start(new ApacheHttpClientRequest(host, request));
return new Object[] {
adviceScope,
// Wrap the handler so we capture the status code
adviceScope == null ? handler : adviceScope.wrapHandler(handler)
};
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Return Object result,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
@Advice.Enter Object[] enterResult) {

scope.close();
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
AdviceScope adviceScope = (AdviceScope) enterResult[0];
if (adviceScope != null) {
adviceScope.end(result, throwable);
}
}
}
}
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 ApacheHttpClientInstrumentationModule extends InstrumentationModule {
public class ApacheHttpClientInstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {

public ApacheHttpClientInstrumentationModule() {
super("apache-httpclient", "apache-httpclient-4.0");
Expand All @@ -23,4 +25,9 @@ public ApacheHttpClientInstrumentationModule() {
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new ApacheHttpClientInstrumentation());
}

@Override
public boolean isIndyReady() {
return true;
}
}
Loading
Loading