Pre- update apache-httpasyncclient-4.1 to Instrumenter API (#3209)
This commit is contained in:
parent
59abf0380f
commit
097ce893d3
|
@ -14,7 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.Span;
|
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
@ -33,6 +32,8 @@ import org.apache.http.nio.IOControl;
|
||||||
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
|
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
|
||||||
import org.apache.http.protocol.HttpContext;
|
import org.apache.http.protocol.HttpContext;
|
||||||
import org.apache.http.protocol.HttpCoreContext;
|
import org.apache.http.protocol.HttpCoreContext;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation {
|
public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
|
@ -66,39 +67,33 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
||||||
public static void methodEnter(
|
public static void methodEnter(
|
||||||
@Advice.Argument(value = 0, readOnly = false) HttpAsyncRequestProducer requestProducer,
|
@Advice.Argument(value = 0, readOnly = false) HttpAsyncRequestProducer requestProducer,
|
||||||
@Advice.Argument(2) HttpContext httpContext,
|
@Advice.Argument(2) HttpContext httpContext,
|
||||||
@Advice.Argument(value = 3, readOnly = false) FutureCallback<?> futureCallback,
|
@Advice.Argument(value = 3, readOnly = false) FutureCallback<?> futureCallback) {
|
||||||
@Advice.Local("otelContext") Context context) {
|
|
||||||
|
|
||||||
Context parentContext = currentContext();
|
Context parentContext = currentContext();
|
||||||
if (!tracer().shouldStartSpan(parentContext)) {
|
if (!tracer().shouldStartSpan(parentContext)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = tracer().startSpan(parentContext);
|
WrappedFutureCallback<?> wrappedFutureCallback =
|
||||||
|
new WrappedFutureCallback<>(parentContext, httpContext, futureCallback);
|
||||||
requestProducer = new DelegatingRequestProducer(context, requestProducer);
|
requestProducer =
|
||||||
futureCallback =
|
new DelegatingRequestProducer(parentContext, requestProducer, wrappedFutureCallback);
|
||||||
new TraceContinuedFutureCallback<>(parentContext, context, httpContext, futureCallback);
|
futureCallback = wrappedFutureCallback;
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
|
||||||
public static void methodExit(
|
|
||||||
@Advice.Return Object result,
|
|
||||||
@Advice.Thrown Throwable throwable,
|
|
||||||
@Advice.Local("otelContext") Context context) {
|
|
||||||
if (context != null && throwable != null) {
|
|
||||||
tracer().endExceptionally(context, throwable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DelegatingRequestProducer implements HttpAsyncRequestProducer {
|
public static class DelegatingRequestProducer implements HttpAsyncRequestProducer {
|
||||||
private final Context context;
|
private final Context parentContext;
|
||||||
private final HttpAsyncRequestProducer delegate;
|
private final HttpAsyncRequestProducer delegate;
|
||||||
|
private final WrappedFutureCallback<?> wrappedFutureCallback;
|
||||||
|
|
||||||
public DelegatingRequestProducer(Context context, HttpAsyncRequestProducer delegate) {
|
public DelegatingRequestProducer(
|
||||||
this.context = context;
|
Context parentContext,
|
||||||
|
HttpAsyncRequestProducer delegate,
|
||||||
|
WrappedFutureCallback<?> wrappedFutureCallback) {
|
||||||
|
this.parentContext = parentContext;
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
|
this.wrappedFutureCallback = wrappedFutureCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,10 +104,7 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
||||||
@Override
|
@Override
|
||||||
public HttpRequest generateRequest() throws IOException, HttpException {
|
public HttpRequest generateRequest() throws IOException, HttpException {
|
||||||
HttpRequest request = delegate.generateRequest();
|
HttpRequest request = delegate.generateRequest();
|
||||||
tracer().inject(context, request);
|
wrappedFutureCallback.context = tracer().startSpan(parentContext, request, request);
|
||||||
Span span = Span.fromContext(context);
|
|
||||||
span.updateName(tracer().spanNameForRequest(request));
|
|
||||||
tracer().onRequest(span, request);
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,31 +137,21 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
delegate.close();
|
delegate.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes context associated with the client invocation. Extending instrumentations can use
|
|
||||||
* this to access client span.
|
|
||||||
*
|
|
||||||
* @return context associated with the invocation.
|
|
||||||
*/
|
|
||||||
public Context getContext() {
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TraceContinuedFutureCallback<T> implements FutureCallback<T> {
|
public static class WrappedFutureCallback<T> implements FutureCallback<T> {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(WrappedFutureCallback.class);
|
||||||
|
|
||||||
private final Context parentContext;
|
private final Context parentContext;
|
||||||
private final Context context;
|
|
||||||
private final HttpContext httpContext;
|
private final HttpContext httpContext;
|
||||||
private final FutureCallback<T> delegate;
|
private final FutureCallback<T> delegate;
|
||||||
|
|
||||||
public TraceContinuedFutureCallback(
|
private volatile Context context;
|
||||||
Context parentContext,
|
|
||||||
Context context,
|
public WrappedFutureCallback(
|
||||||
HttpContext httpContext,
|
Context parentContext, HttpContext httpContext, FutureCallback<T> delegate) {
|
||||||
FutureCallback<T> delegate) {
|
|
||||||
this.parentContext = parentContext;
|
this.parentContext = parentContext;
|
||||||
this.context = context;
|
|
||||||
this.httpContext = httpContext;
|
this.httpContext = httpContext;
|
||||||
// Note: this can be null in real life, so we have to handle this carefully
|
// Note: this can be null in real life, so we have to handle this carefully
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
|
@ -177,42 +159,66 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(T result) {
|
public void completed(T result) {
|
||||||
|
if (context == null) {
|
||||||
|
// this is unexpected
|
||||||
|
logger.debug("context was never set");
|
||||||
|
completeDelegate(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tracer().end(context, getResponse(httpContext));
|
tracer().end(context, getResponse(httpContext));
|
||||||
|
|
||||||
if (parentContext == null) {
|
if (parentContext == null) {
|
||||||
completeDelegate(result);
|
completeDelegate(result);
|
||||||
} else {
|
return;
|
||||||
try (Scope ignored = parentContext.makeCurrent()) {
|
}
|
||||||
completeDelegate(result);
|
|
||||||
}
|
try (Scope ignored = parentContext.makeCurrent()) {
|
||||||
|
completeDelegate(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Exception ex) {
|
public void failed(Exception ex) {
|
||||||
|
if (context == null) {
|
||||||
|
// this is unexpected
|
||||||
|
logger.debug("context was never set");
|
||||||
|
failDelegate(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// end span before calling delegate
|
// end span before calling delegate
|
||||||
tracer().endExceptionally(context, getResponse(httpContext), ex);
|
tracer().endExceptionally(context, getResponse(httpContext), ex);
|
||||||
|
|
||||||
if (parentContext == null) {
|
if (parentContext == null) {
|
||||||
failDelegate(ex);
|
failDelegate(ex);
|
||||||
} else {
|
return;
|
||||||
try (Scope ignored = parentContext.makeCurrent()) {
|
}
|
||||||
failDelegate(ex);
|
|
||||||
}
|
try (Scope ignored = parentContext.makeCurrent()) {
|
||||||
|
failDelegate(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancelled() {
|
public void cancelled() {
|
||||||
|
if (context == null) {
|
||||||
|
// this is unexpected
|
||||||
|
logger.debug("context was never set");
|
||||||
|
cancelDelegate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// end span before calling delegate
|
// end span before calling delegate
|
||||||
tracer().end(context, getResponse(httpContext));
|
tracer().end(context, getResponse(httpContext));
|
||||||
|
|
||||||
if (parentContext == null) {
|
if (parentContext == null) {
|
||||||
cancelDelegate();
|
cancelDelegate();
|
||||||
} else {
|
return;
|
||||||
try (Scope ignored = parentContext.makeCurrent()) {
|
}
|
||||||
cancelDelegate();
|
|
||||||
}
|
try (Scope ignored = parentContext.makeCurrent()) {
|
||||||
|
cancelDelegate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue