Skip to content

Commit

Permalink
Moves http async client 4.1 to use commons module
Browse files Browse the repository at this point in the history
  • Loading branch information
anuragagarwal561994 committed Feb 27, 2023
1 parent c4c04fd commit efc2b32
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 508 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ muzzle {
}

dependencies {
implementation(project(":instrumentation:apache-httpclient:commons:javaagent"))
implementation(project(":instrumentation:apache-httpclient:commons-4.0:javaagent"))
library("org.apache.httpcomponents:httpasyncclient:4.1")
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,23 @@
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.io.IOException;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.nio.ContentEncoder;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;

public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation {
public final class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<ClassLoader> classLoaderOptimization() {
Expand Down Expand Up @@ -66,193 +55,20 @@ public static class ClientAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(
@Advice.Argument(value = 0, readOnly = false) HttpAsyncRequestProducer requestProducer,
@Advice.Argument(2) HttpContext httpContext,
@Advice.Argument(value = 2, readOnly = false) HttpContext httpContext,
@Advice.Argument(value = 3, readOnly = false) FutureCallback<?> futureCallback) {

Context parentContext = currentContext();
if (httpContext == null) {
httpContext = new BasicHttpContext();
}

WrappedFutureCallback<?> wrappedFutureCallback =
new WrappedFutureCallback<>(parentContext, httpContext, futureCallback);
new WrappedFutureCallback<>(parentContext, futureCallback);
requestProducer =
new DelegatingRequestProducer(parentContext, requestProducer, wrappedFutureCallback);
new WrappedRequestProducer(
parentContext, requestProducer, wrappedFutureCallback);
futureCallback = wrappedFutureCallback;
}
}

public static class DelegatingRequestProducer implements HttpAsyncRequestProducer {
private final Context parentContext;
private final HttpAsyncRequestProducer delegate;
private final WrappedFutureCallback<?> wrappedFutureCallback;

public DelegatingRequestProducer(
Context parentContext,
HttpAsyncRequestProducer delegate,
WrappedFutureCallback<?> wrappedFutureCallback) {
this.parentContext = parentContext;
this.delegate = delegate;
this.wrappedFutureCallback = wrappedFutureCallback;
}

@Override
public HttpHost getTarget() {
return delegate.getTarget();
}

@Override
public HttpRequest generateRequest() throws IOException, HttpException {
HttpHost target = delegate.getTarget();
HttpRequest request = delegate.generateRequest();

ApacheHttpClientRequest otelRequest = new ApacheHttpClientRequest(target, request);

if (instrumenter().shouldStart(parentContext, otelRequest)) {
wrappedFutureCallback.context = instrumenter().start(parentContext, otelRequest);
wrappedFutureCallback.otelRequest = otelRequest;
}

return request;
}

@Override
public void produceContent(ContentEncoder encoder, IOControl ioctrl) throws IOException {
delegate.produceContent(encoder, ioctrl);
}

@Override
public void requestCompleted(HttpContext context) {
delegate.requestCompleted(context);
}

@Override
public void failed(Exception ex) {
delegate.failed(ex);
}

@Override
public boolean isRepeatable() {
return delegate.isRepeatable();
}

@Override
public void resetRequest() throws IOException {
delegate.resetRequest();
}

@Override
public void close() throws IOException {
delegate.close();
}
}

public static class WrappedFutureCallback<T> implements FutureCallback<T> {

private static final Logger logger = Logger.getLogger(WrappedFutureCallback.class.getName());

private final Context parentContext;
@Nullable private final HttpContext httpContext;
private final FutureCallback<T> delegate;

private volatile Context context;
private volatile ApacheHttpClientRequest otelRequest;

public WrappedFutureCallback(
Context parentContext, HttpContext httpContext, FutureCallback<T> delegate) {
this.parentContext = parentContext;
this.httpContext = httpContext;
// Note: this can be null in real life, so we have to handle this carefully
this.delegate = delegate;
}

@Override
public void completed(T result) {
if (context == null) {
// this is unexpected
logger.fine("context was never set");
completeDelegate(result);
return;
}

instrumenter().end(context, otelRequest, getResponseFromHttpContext(), null);

if (parentContext == null) {
completeDelegate(result);
return;
}

try (Scope ignored = parentContext.makeCurrent()) {
completeDelegate(result);
}
}

@Override
public void failed(Exception ex) {
if (context == null) {
// this is unexpected
logger.fine("context was never set");
failDelegate(ex);
return;
}

// end span before calling delegate
instrumenter().end(context, otelRequest, getResponseFromHttpContext(), ex);

if (parentContext == null) {
failDelegate(ex);
return;
}

try (Scope ignored = parentContext.makeCurrent()) {
failDelegate(ex);
}
}

@Override
public void cancelled() {
if (context == null) {
// this is unexpected
logger.fine("context was never set");
cancelDelegate();
return;
}

// TODO (trask) add "canceled" span attribute
// end span before calling delegate
instrumenter().end(context, otelRequest, getResponseFromHttpContext(), null);

if (parentContext == null) {
cancelDelegate();
return;
}

try (Scope ignored = parentContext.makeCurrent()) {
cancelDelegate();
}
}

private void completeDelegate(T result) {
if (delegate != null) {
delegate.completed(result);
}
}

private void failDelegate(Exception ex) {
if (delegate != null) {
delegate.failed(ex);
}
}

private void cancelDelegate() {
if (delegate != null) {
delegate.cancelled();
}
}

@Nullable
private HttpResponse getResponseFromHttpContext() {
if (httpContext == null) {
return null;
}
return (HttpResponse) httpContext.getAttribute(HttpCoreContext.HTTP_RESPONSE);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@

package io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient;

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 java.util.ArrayList;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class ApacheHttpAsyncClientInstrumentationModule extends InstrumentationModule {
public final class ApacheHttpAsyncClientInstrumentationModule extends InstrumentationModule {
public ApacheHttpAsyncClientInstrumentationModule() {
super("apache-httpasyncclient", "apache-httpasyncclient-4.1");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new ApacheHttpAsyncClientInstrumentation());
List<TypeInstrumentation> instrumentationList = new ArrayList<>();
instrumentationList.add(new ApacheHttpAsyncClientInstrumentation());
return instrumentationList;
}
}

This file was deleted.

Loading

0 comments on commit efc2b32

Please sign in to comment.