Simplify jetty9 http client instrumentation (#11595)

This commit is contained in:
Lauri Tulmin 2024-06-19 02:09:34 +03:00 committed by GitHub
parent 1565d18197
commit de11929bea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 68 deletions

View File

@ -14,7 +14,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope; import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal.JettyHttpClient9TracingInterceptor; import io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal.JettyClientTracingListener;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.List; import java.util.List;
@ -50,19 +50,13 @@ public class JettyHttpClient9Instrumentation implements TypeInstrumentation {
@Advice.Local("otelContext") Context context, @Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) { @Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext(); Context parentContext = currentContext();
if (!instrumenter().shouldStart(parentContext, httpRequest)) { context =
JettyClientTracingListener.handleRequest(parentContext, httpRequest, instrumenter());
if (context == null) {
return; return;
} }
// First step is to attach the tracer to the Jetty request. Request listeners are wrapped here
JettyHttpClient9TracingInterceptor requestInterceptor =
new JettyHttpClient9TracingInterceptor(parentContext, instrumenter());
requestInterceptor.attachToRequest(httpRequest);
// Second step is to wrap all the important result callback
listeners = wrapResponseListeners(parentContext, listeners); listeners = wrapResponseListeners(parentContext, listeners);
context = requestInterceptor.getContext();
scope = context.makeCurrent(); scope = context.makeCurrent();
} }

View File

@ -9,7 +9,7 @@ import static io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal.Je
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal.JettyHttpClient9TracingInterceptor; import io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal.JettyClientTracingListener;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpClientTransport;
@ -60,10 +60,12 @@ class TracingHttpClient extends HttpClient {
@Override @Override
protected void send(HttpRequest request, List<Response.ResponseListener> listeners) { protected void send(HttpRequest request, List<Response.ResponseListener> listeners) {
Context parentContext = Context.current(); Context parentContext = Context.current();
JettyHttpClient9TracingInterceptor requestInterceptor = Context context =
new JettyHttpClient9TracingInterceptor(parentContext, this.instrumenter); JettyClientTracingListener.handleRequest(parentContext, request, instrumenter);
requestInterceptor.attachToRequest(request); // wrap listeners only when a span was started (context is not null)
List<Response.ResponseListener> wrapped = wrapResponseListeners(parentContext, listeners); if (context != null) {
super.send(request, wrapped); listeners = wrapResponseListeners(parentContext, listeners);
}
super.send(request, listeners);
} }
} }

View File

@ -15,26 +15,26 @@ import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Response;
/** /**
* JettyHttpClient9TracingInterceptor does three jobs stimulated from the Jetty Request object from * JettyClientTracingListener performs three actions when {@link #handleRequest(Context,
* attachToRequest() 1. Start the CLIENT span and create the tracer 2. Set the listener callbacks * HttpRequest, Instrumenter)} is called 1. Start the CLIENT span 2. Set the listener callbacks for
* for each important lifecycle actions that would cause the start and close of the span 3. Set * each lifecycle action that signal end of the request 3. Wrap request listeners to propagate
* callback wrappers on two important request-based callbacks * context into the listeners
* *
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change * <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time. * at any time.
*/ */
public final class JettyHttpClient9TracingInterceptor public final class JettyClientTracingListener
implements Request.BeginListener, implements Request.BeginListener,
Request.FailureListener, Request.FailureListener,
Response.SuccessListener, Response.SuccessListener,
Response.FailureListener { Response.FailureListener {
private static final Logger logger = private static final Logger logger = Logger.getLogger(JettyClientTracingListener.class.getName());
Logger.getLogger(JettyHttpClient9TracingInterceptor.class.getName());
private static final Class<?>[] requestlistenerInterfaces = { private static final Class<?>[] requestlistenerInterfaces = {
Request.BeginListener.class, Request.BeginListener.class,
@ -46,46 +46,48 @@ public final class JettyHttpClient9TracingInterceptor
Request.QueuedListener.class Request.QueuedListener.class
}; };
@Nullable private Context context; private final Context context;
@Nullable
public Context getContext() {
return this.context;
}
private final Context parentContext;
private final Instrumenter<Request, Response> instrumenter; private final Instrumenter<Request, Response> instrumenter;
public JettyHttpClient9TracingInterceptor( private JettyClientTracingListener(
Context parentCtx, Instrumenter<Request, Response> instrumenter) { Context context, Instrumenter<Request, Response> instrumenter) {
this.parentContext = parentCtx; this.context = context;
this.instrumenter = instrumenter; this.instrumenter = instrumenter;
} }
public void attachToRequest(Request jettyRequest) { @Nullable
List<JettyHttpClient9TracingInterceptor> current = public static Context handleRequest(
jettyRequest.getRequestListeners(JettyHttpClient9TracingInterceptor.class); Context parentContext, HttpRequest request, Instrumenter<Request, Response> instrumenter) {
List<JettyClientTracingListener> current =
request.getRequestListeners(JettyClientTracingListener.class);
if (!current.isEmpty()) { if (!current.isEmpty()) {
logger.warning("A tracing interceptor is already in place for this request!"); logger.warning("A tracing request listener is already in place for this request!");
return; return null;
} }
startSpan(jettyRequest);
if (!instrumenter.shouldStart(parentContext, request)) {
return null;
}
Context context = instrumenter.start(parentContext, request);
// wrap all important request-based listeners that may already be attached, null should ensure // wrap all important request-based listeners that may already be attached, null should ensure
// are returned here // that all listeners are returned here
List<Request.RequestListener> existingListeners = jettyRequest.getRequestListeners(null); List<Request.RequestListener> existingListeners = request.getRequestListeners(null);
wrapRequestListeners(existingListeners); wrapRequestListeners(existingListeners, context);
jettyRequest JettyClientTracingListener listener = new JettyClientTracingListener(context, instrumenter);
.onRequestBegin(this) request
.onRequestFailure(this) .onRequestBegin(listener)
.onResponseFailure(this) .onRequestFailure(listener)
.onResponseSuccess(this); .onResponseFailure(listener)
.onResponseSuccess(listener);
return context;
} }
private void wrapRequestListeners(List<Request.RequestListener> requestListeners) { private static void wrapRequestListeners(
List<Request.RequestListener> requestListeners, Context context) {
ListIterator<Request.RequestListener> iterator = requestListeners.listIterator(); ListIterator<Request.RequestListener> iterator = requestListeners.listIterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
@ -121,34 +123,21 @@ public final class JettyHttpClient9TracingInterceptor
} }
} }
private void startSpan(Request request) {
if (!instrumenter.shouldStart(this.parentContext, request)) {
return;
}
this.context = instrumenter.start(this.parentContext, request);
}
@Override @Override
public void onBegin(Request request) {} public void onBegin(Request request) {}
@Override @Override
public void onSuccess(Response response) { public void onSuccess(Response response) {
if (this.context != null) { instrumenter.end(this.context, response.getRequest(), response, null);
instrumenter.end(this.context, response.getRequest(), response, null);
}
} }
@Override @Override
public void onFailure(Request request, Throwable t) { public void onFailure(Request request, Throwable t) {
if (this.context != null) { instrumenter.end(this.context, request, null, t);
instrumenter.end(this.context, request, null, t);
}
} }
@Override @Override
public void onFailure(Response response, Throwable t) { public void onFailure(Response response, Throwable t) {
if (this.context != null) { instrumenter.end(this.context, response.getRequest(), response, t);
instrumenter.end(this.context, response.getRequest(), response, t);
}
} }
} }

View File

@ -50,7 +50,7 @@ public final class JettyClientWrapUtil {
private static Response.ResponseListener wrapTheListener( private static Response.ResponseListener wrapTheListener(
Response.ResponseListener listener, Context context) { Response.ResponseListener listener, Context context) {
if (listener == null || listener instanceof JettyHttpClient9TracingInterceptor) { if (listener == null || listener instanceof JettyClientTracingListener) {
return listener; return listener;
} }