Use Context more in HttpClientTracer (#1811)
* Use Context more in HttpClientTracer * Better http-url-connection response object * Follow database semantic conv for elasticsearch-rest * Remove unnecessary CallDepth tracking
This commit is contained in:
parent
54e3df3cd4
commit
65f54e450b
|
@ -12,7 +12,6 @@ import io.opentelemetry.api.trace.SpanBuilder;
|
|||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils;
|
||||
|
@ -60,60 +59,63 @@ public abstract class HttpClientTracer<REQUEST, CARRIER, RESPONSE> extends BaseT
|
|||
super(tracer);
|
||||
}
|
||||
|
||||
public Span startSpan(REQUEST request) {
|
||||
return startSpan(request, -1);
|
||||
public boolean shouldStartSpan(Context parentContext) {
|
||||
return parentContext.get(CONTEXT_CLIENT_SPAN_KEY) == null;
|
||||
}
|
||||
|
||||
public Span startSpan(REQUEST request, long startTimeNanos) {
|
||||
return internalStartSpan(request, spanNameForRequest(request), startTimeNanos);
|
||||
public Context startSpan(Context parentContext, REQUEST request, CARRIER carrier) {
|
||||
return startSpan(parentContext, request, carrier, -1);
|
||||
}
|
||||
|
||||
public Scope startScope(Span span, CARRIER carrier) {
|
||||
Context context = Context.current().with(span);
|
||||
|
||||
public Context startSpan(
|
||||
Context parentContext, REQUEST request, CARRIER carrier, long startTimeNanos) {
|
||||
Span span =
|
||||
internalStartSpan(parentContext, request, spanNameForRequest(request), startTimeNanos);
|
||||
Setter<CARRIER> setter = getSetter();
|
||||
if (setter == null) {
|
||||
throw new IllegalStateException(
|
||||
"getSetter() not defined but calling startScope(), either getSetter must be implemented or the scope should be setup manually");
|
||||
}
|
||||
Context context = parentContext.with(span).with(CONTEXT_CLIENT_SPAN_KEY, span);
|
||||
OpenTelemetry.getGlobalPropagators().getTextMapPropagator().inject(context, carrier, setter);
|
||||
context = context.with(CONTEXT_CLIENT_SPAN_KEY, span);
|
||||
return context.makeCurrent();
|
||||
return context;
|
||||
}
|
||||
|
||||
public void end(Span span, RESPONSE response) {
|
||||
end(span, response, -1);
|
||||
public void end(Context context, RESPONSE response) {
|
||||
end(context, response, -1);
|
||||
}
|
||||
|
||||
public void end(Span span, RESPONSE response, long endTimeNanos) {
|
||||
public void end(Context context, RESPONSE response, long endTimeNanos) {
|
||||
Span span = Span.fromContext(context);
|
||||
onResponse(span, response);
|
||||
super.end(span, endTimeNanos);
|
||||
}
|
||||
|
||||
public void endExceptionally(Span span, RESPONSE response, Throwable throwable) {
|
||||
endExceptionally(span, response, throwable, -1);
|
||||
public void end(Context context) {
|
||||
Span span = Span.fromContext(context);
|
||||
super.end(span);
|
||||
}
|
||||
|
||||
public void endExceptionally(Context context, RESPONSE response, Throwable throwable) {
|
||||
endExceptionally(context, response, throwable, -1);
|
||||
}
|
||||
|
||||
public void endExceptionally(
|
||||
Span span, RESPONSE response, Throwable throwable, long endTimeNanos) {
|
||||
Context context, RESPONSE response, Throwable throwable, long endTimeNanos) {
|
||||
Span span = Span.fromContext(context);
|
||||
onResponse(span, response);
|
||||
super.endExceptionally(span, throwable, endTimeNanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new client {@link Span} if there is no client {@link Span} in the current {@link
|
||||
* Context}, or an invalid {@link Span} otherwise.
|
||||
*/
|
||||
private Span internalStartSpan(REQUEST request, String name, long startTimeNanos) {
|
||||
Context context = Context.current();
|
||||
Span clientSpan = context.get(CONTEXT_CLIENT_SPAN_KEY);
|
||||
public void endExceptionally(Context context, Throwable throwable) {
|
||||
Span span = Span.fromContext(context);
|
||||
super.endExceptionally(span, throwable, -1);
|
||||
}
|
||||
|
||||
if (clientSpan != null) {
|
||||
// We don't want to create two client spans for a given client call, suppress inner spans.
|
||||
return Span.getInvalid();
|
||||
}
|
||||
|
||||
SpanBuilder spanBuilder = tracer.spanBuilder(name).setSpanKind(Kind.CLIENT).setParent(context);
|
||||
private Span internalStartSpan(
|
||||
Context parentContext, REQUEST request, String name, long startTimeNanos) {
|
||||
SpanBuilder spanBuilder =
|
||||
tracer.spanBuilder(name).setSpanKind(Kind.CLIENT).setParent(parentContext);
|
||||
if (startTimeNanos > 0) {
|
||||
spanBuilder.setStartTimestamp(startTimeNanos, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.akkahttp;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
|
@ -14,10 +15,9 @@ import akka.http.scaladsl.HttpExt;
|
|||
import akka.http.scaladsl.model.HttpRequest;
|
||||
import akka.http.scaladsl.model.HttpResponse;
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.util.Collections;
|
||||
|
@ -70,23 +70,24 @@ public class AkkaHttpClientInstrumentationModule extends InstrumentationModule {
|
|||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(value = 0, readOnly = false) HttpRequest request,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
/*
|
||||
Versions 10.0 and 10.1 have slightly different structure that is hard to distinguish so here
|
||||
we cast 'wider net' and avoid instrumenting twice.
|
||||
In the future we may want to separate these, but since lots of code is reused we would need to come up
|
||||
with way of continuing to reusing it.
|
||||
*/
|
||||
callDepth = tracer().getCallDepth();
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
span = tracer().startSpan(request);
|
||||
// Request is immutable, so we have to assign new value once we update headers
|
||||
AkkaHttpHeaders headers = new AkkaHttpHeaders(request);
|
||||
scope = tracer().startScope(span, headers);
|
||||
request = headers.getRequest();
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Request is immutable, so we have to assign new value once we update headers
|
||||
AkkaHttpHeaders headers = new AkkaHttpHeaders(request);
|
||||
context = tracer().startSpan(parentContext, request, headers);
|
||||
scope = context.makeCurrent();
|
||||
request = headers.getRequest();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
|
@ -95,33 +96,34 @@ public class AkkaHttpClientInstrumentationModule extends InstrumentationModule {
|
|||
@Advice.This HttpExt thiz,
|
||||
@Advice.Return Future<HttpResponse> responseFuture,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
if (callDepth.decrementAndGet() == 0 && scope != null) {
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
responseFuture.onComplete(new OnCompleteHandler(span), thiz.system().dispatcher());
|
||||
} else {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
}
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
responseFuture.onComplete(new OnCompleteHandler(context), thiz.system().dispatcher());
|
||||
} else {
|
||||
tracer().endExceptionally(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnCompleteHandler extends AbstractFunction1<Try<HttpResponse>, Void> {
|
||||
private final Span span;
|
||||
private final Context context;
|
||||
|
||||
public OnCompleteHandler(Span span) {
|
||||
this.span = span;
|
||||
public OnCompleteHandler(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(Try<HttpResponse> result) {
|
||||
if (result.isSuccess()) {
|
||||
tracer().end(span, result.get());
|
||||
tracer().end(context, result.get());
|
||||
} else {
|
||||
tracer().endExceptionally(span, result.failed().get());
|
||||
tracer().endExceptionally(context, result.failed().get());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -8,14 +8,11 @@ package io.opentelemetry.javaagent.instrumentation.akkahttp;
|
|||
import static io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientInstrumentationModule.InjectAdapter.SETTER;
|
||||
|
||||
import akka.http.javadsl.model.HttpHeader;
|
||||
import akka.http.scaladsl.HttpExt;
|
||||
import akka.http.scaladsl.model.HttpRequest;
|
||||
import akka.http.scaladsl.model.HttpResponse;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientInstrumentationModule.AkkaHttpHeaders;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
|
@ -27,10 +24,6 @@ public class AkkaHttpClientTracer
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
public Depth getCallDepth() {
|
||||
return CallDepthThreadLocalMap.getCallDepth(HttpExt.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(HttpRequest httpRequest) {
|
||||
return httpRequest.method().value();
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.tracer.HttpClientTracer.DEFAULT_SPAN_NAME;
|
||||
import static io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
|
||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
@ -15,11 +15,10 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.Span.Kind;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
@ -66,36 +65,41 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
|||
public static class ClientAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static Span methodEnter(
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(value = 0, readOnly = false) HttpAsyncRequestProducer requestProducer,
|
||||
@Advice.Argument(2) HttpContext context,
|
||||
@Advice.Argument(value = 3, readOnly = false) FutureCallback<?> futureCallback) {
|
||||
@Advice.Argument(2) HttpContext httpContext,
|
||||
@Advice.Argument(value = 3, readOnly = false) FutureCallback<?> futureCallback,
|
||||
@Advice.Local("otelContext") Context context) {
|
||||
|
||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||
Span clientSpan = tracer().startSpan(DEFAULT_SPAN_NAME, Kind.CLIENT);
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
requestProducer = new DelegatingRequestProducer(clientSpan, requestProducer);
|
||||
context = tracer().startSpan(parentContext);
|
||||
|
||||
requestProducer = new DelegatingRequestProducer(context, requestProducer);
|
||||
futureCallback =
|
||||
new TraceContinuedFutureCallback<>(parentContext, clientSpan, context, futureCallback);
|
||||
|
||||
return clientSpan;
|
||||
new TraceContinuedFutureCallback<>(parentContext, context, httpContext, futureCallback);
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter Span span, @Advice.Return Object result, @Advice.Thrown Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
@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 {
|
||||
Span span;
|
||||
Context context;
|
||||
HttpAsyncRequestProducer delegate;
|
||||
|
||||
public DelegatingRequestProducer(Span span, HttpAsyncRequestProducer delegate) {
|
||||
this.span = span;
|
||||
public DelegatingRequestProducer(Context context, HttpAsyncRequestProducer delegate) {
|
||||
this.context = context;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
|
@ -107,13 +111,12 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
|||
@Override
|
||||
public HttpRequest generateRequest() throws IOException, HttpException {
|
||||
HttpRequest request = delegate.generateRequest();
|
||||
OpenTelemetry.getGlobalPropagators()
|
||||
.getTextMapPropagator()
|
||||
.inject(context, request, tracer().getSetter());
|
||||
Span span = Span.fromContext(context);
|
||||
span.updateName(tracer().spanNameForRequest(request));
|
||||
tracer().onRequest(span, request);
|
||||
|
||||
// TODO (trask) expose inject separate from startScope, e.g. for async cases
|
||||
Scope scope = tracer().startScope(span, request);
|
||||
scope.close();
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
|
@ -150,22 +153,25 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
|||
|
||||
public static class TraceContinuedFutureCallback<T> implements FutureCallback<T> {
|
||||
private final Context parentContext;
|
||||
private final Span clientSpan;
|
||||
private final HttpContext context;
|
||||
private final Context context;
|
||||
private final HttpContext httpContext;
|
||||
private final FutureCallback<T> delegate;
|
||||
|
||||
public TraceContinuedFutureCallback(
|
||||
Context parentContext, Span clientSpan, HttpContext context, FutureCallback<T> delegate) {
|
||||
Context parentContext,
|
||||
Context context,
|
||||
HttpContext httpContext,
|
||||
FutureCallback<T> delegate) {
|
||||
this.parentContext = parentContext;
|
||||
this.clientSpan = clientSpan;
|
||||
this.context = context;
|
||||
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) {
|
||||
tracer().end(clientSpan, getResponse(context));
|
||||
tracer().end(context, getResponse(httpContext));
|
||||
|
||||
if (parentContext == null) {
|
||||
completeDelegate(result);
|
||||
|
@ -179,7 +185,7 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
|||
@Override
|
||||
public void failed(Exception ex) {
|
||||
// end span before calling delegate
|
||||
tracer().endExceptionally(clientSpan, getResponse(context), ex);
|
||||
tracer().endExceptionally(context, getResponse(httpContext), ex);
|
||||
|
||||
if (parentContext == null) {
|
||||
failDelegate(ex);
|
||||
|
@ -193,7 +199,7 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation
|
|||
@Override
|
||||
public void cancelled() {
|
||||
// end span before calling delegate
|
||||
tracer().end(clientSpan, getResponse(context));
|
||||
tracer().end(context, getResponse(httpContext));
|
||||
|
||||
if (parentContext == null) {
|
||||
cancelDelegate();
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient;
|
||||
|
||||
import static io.opentelemetry.api.trace.Span.Kind.CLIENT;
|
||||
import static io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient.HttpHeadersInjectAdapter.SETTER;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import java.net.URI;
|
||||
|
@ -30,6 +32,16 @@ public class ApacheHttpAsyncClientTracer
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext) {
|
||||
Span span =
|
||||
tracer
|
||||
.spanBuilder(DEFAULT_SPAN_NAME)
|
||||
.setSpanKind(CLIENT)
|
||||
.setParent(parentContext)
|
||||
.startSpan();
|
||||
return parentContext.with(span).with(CONTEXT_CLIENT_SPAN_KEY, span);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(HttpRequest request) {
|
||||
if (request instanceof HttpUriRequest) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0.CommonsHttpClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
|
||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
@ -16,9 +17,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.util.List;
|
||||
|
@ -67,34 +67,32 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule
|
|||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(1) HttpMethod httpMethod,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
|
||||
callDepth = tracer().getCallDepth();
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
span = tracer().startSpan(httpMethod);
|
||||
if (span.getSpanContext().isValid()) {
|
||||
scope = tracer().startScope(span, httpMethod);
|
||||
}
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
context = tracer().startSpan(parentContext, httpMethod, httpMethod);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Argument(1) HttpMethod httpMethod,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callDepth.decrementAndGet() == 0 && scope != null) {
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
tracer().end(span, httpMethod);
|
||||
} else {
|
||||
tracer().endExceptionally(span, httpMethod, throwable);
|
||||
}
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
tracer().end(context, httpMethod);
|
||||
} else {
|
||||
tracer().endExceptionally(context, httpMethod, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0;
|
|||
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import org.apache.commons.httpclient.Header;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.HttpMethod;
|
||||
import org.apache.commons.httpclient.StatusLine;
|
||||
import org.apache.commons.httpclient.URIException;
|
||||
|
@ -29,10 +26,6 @@ public class CommonsHttpClientTracer extends HttpClientTracer<HttpMethod, HttpMe
|
|||
return "io.opentelemetry.javaagent.apache-httpclient";
|
||||
}
|
||||
|
||||
public Depth getCallDepth() {
|
||||
return CallDepthThreadLocalMap.getCallDepth(HttpClient.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(HttpMethod httpMethod) {
|
||||
return httpMethod.getName();
|
||||
|
|
|
@ -8,44 +8,20 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0;
|
|||
import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
|
||||
public class ApacheHttpClientHelper {
|
||||
|
||||
public static SpanWithScope doMethodEnter(HttpUriRequest request) {
|
||||
Span span = tracer().startSpan(request);
|
||||
Scope scope = tracer().startScope(span, request);
|
||||
return new SpanWithScope(span, scope);
|
||||
}
|
||||
public static void doMethodExit(Context context, Object result, Throwable throwable) {
|
||||
if (result instanceof HttpResponse) {
|
||||
tracer().onResponse(Span.fromContext(context), (HttpResponse) result);
|
||||
} // else they probably provided a ResponseHandler
|
||||
|
||||
public static void doMethodExitAndResetCallDepthThread(
|
||||
SpanWithScope spanWithScope, Object result, Throwable throwable) {
|
||||
if (spanWithScope == null) {
|
||||
return;
|
||||
}
|
||||
CallDepthThreadLocalMap.reset(HttpClient.class);
|
||||
|
||||
doMethodExit(spanWithScope, result, throwable);
|
||||
}
|
||||
|
||||
public static void doMethodExit(SpanWithScope spanWithScope, Object result, Throwable throwable) {
|
||||
try {
|
||||
Span span = spanWithScope.getSpan();
|
||||
if (result instanceof HttpResponse) {
|
||||
tracer().onResponse(span, (HttpResponse) result);
|
||||
} // else they probably provided a ResponseHandler
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
} else {
|
||||
tracer().end(span);
|
||||
}
|
||||
} finally {
|
||||
spanWithScope.closeScope();
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(context, throwable);
|
||||
} else {
|
||||
tracer().end(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
|
||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
@ -16,8 +18,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.util.HashMap;
|
||||
|
@ -30,7 +32,6 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
|||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.ResponseHandler;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
|
||||
|
@ -147,90 +148,117 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule
|
|||
|
||||
public static class UriRequestAdvice {
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static SpanWithScope methodEnter(@Advice.Argument(0) HttpUriRequest request) {
|
||||
int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class);
|
||||
if (callDepth > 0) {
|
||||
return null;
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(0) HttpUriRequest request,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ApacheHttpClientHelper.doMethodEnter(request);
|
||||
context = tracer().startSpan(parentContext, request, request);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter SpanWithScope spanWithScope,
|
||||
@Advice.Return Object result,
|
||||
@Advice.Thrown Throwable throwable) {
|
||||
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
ApacheHttpClientHelper.doMethodExit(context, result, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public static class UriRequestWithHandlerAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static SpanWithScope methodEnter(
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(0) HttpUriRequest request,
|
||||
@Advice.Argument(
|
||||
value = 1,
|
||||
optional = true,
|
||||
typing = Assigner.Typing.DYNAMIC,
|
||||
readOnly = false)
|
||||
Object handler) {
|
||||
int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class);
|
||||
if (callDepth > 0) {
|
||||
return null;
|
||||
Object handler,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpanWithScope spanWithScope = ApacheHttpClientHelper.doMethodEnter(request);
|
||||
context = tracer().startSpan(parentContext, request, request);
|
||||
scope = context.makeCurrent();
|
||||
|
||||
// Wrap the handler so we capture the status code
|
||||
if (handler instanceof ResponseHandler) {
|
||||
handler =
|
||||
new WrappingStatusSettingResponseHandler(
|
||||
spanWithScope.getSpan(), (ResponseHandler) handler);
|
||||
handler = new WrappingStatusSettingResponseHandler(context, (ResponseHandler) handler);
|
||||
}
|
||||
return spanWithScope;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter SpanWithScope spanWithScope,
|
||||
@Advice.Return Object result,
|
||||
@Advice.Thrown Throwable throwable) {
|
||||
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
ApacheHttpClientHelper.doMethodExit(context, result, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RequestAdvice {
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static SpanWithScope methodEnter(
|
||||
@Advice.Argument(0) HttpHost host, @Advice.Argument(1) HttpRequest request) {
|
||||
int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class);
|
||||
if (callDepth > 0) {
|
||||
return null;
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(0) HttpHost host,
|
||||
@Advice.Argument(1) HttpRequest request,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
HttpUriRequest httpUriRequest;
|
||||
if (request instanceof HttpUriRequest) {
|
||||
return ApacheHttpClientHelper.doMethodEnter((HttpUriRequest) request);
|
||||
httpUriRequest = (HttpUriRequest) request;
|
||||
} else {
|
||||
return ApacheHttpClientHelper.doMethodEnter(
|
||||
new HostAndRequestAsHttpUriRequest(host, request));
|
||||
httpUriRequest = new HostAndRequestAsHttpUriRequest(host, request);
|
||||
}
|
||||
context = tracer().startSpan(parentContext, httpUriRequest, httpUriRequest);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter SpanWithScope spanWithScope,
|
||||
@Advice.Return Object result,
|
||||
@Advice.Thrown Throwable throwable) {
|
||||
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
ApacheHttpClientHelper.doMethodExit(context, result, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RequestWithHandlerAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static SpanWithScope methodEnter(
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(0) HttpHost host,
|
||||
@Advice.Argument(1) HttpRequest request,
|
||||
@Advice.Argument(
|
||||
|
@ -238,36 +266,41 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule
|
|||
optional = true,
|
||||
typing = Assigner.Typing.DYNAMIC,
|
||||
readOnly = false)
|
||||
Object handler) {
|
||||
int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class);
|
||||
if (callDepth > 0) {
|
||||
return null;
|
||||
Object handler,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpanWithScope spanWithScope;
|
||||
|
||||
HttpUriRequest httpUriRequest;
|
||||
if (request instanceof HttpUriRequest) {
|
||||
spanWithScope = ApacheHttpClientHelper.doMethodEnter((HttpUriRequest) request);
|
||||
httpUriRequest = (HttpUriRequest) request;
|
||||
} else {
|
||||
spanWithScope =
|
||||
ApacheHttpClientHelper.doMethodEnter(new HostAndRequestAsHttpUriRequest(host, request));
|
||||
httpUriRequest = new HostAndRequestAsHttpUriRequest(host, request);
|
||||
}
|
||||
context = tracer().startSpan(parentContext, httpUriRequest, httpUriRequest);
|
||||
scope = context.makeCurrent();
|
||||
|
||||
// Wrap the handler so we capture the status code
|
||||
if (handler instanceof ResponseHandler) {
|
||||
handler =
|
||||
new WrappingStatusSettingResponseHandler(
|
||||
spanWithScope.getSpan(), (ResponseHandler) handler);
|
||||
handler = new WrappingStatusSettingResponseHandler(context, (ResponseHandler) handler);
|
||||
}
|
||||
return spanWithScope;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter SpanWithScope spanWithScope,
|
||||
@Advice.Return Object result,
|
||||
@Advice.Thrown Throwable throwable) {
|
||||
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
ApacheHttpClientHelper.doMethodExit(context, result, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.apache.http.HttpResponse;
|
|||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
class ApacheHttpClientTracer
|
||||
public class ApacheHttpClientTracer
|
||||
extends HttpClientTracer<HttpUriRequest, HttpUriRequest, HttpResponse> {
|
||||
|
||||
private static final ApacheHttpClientTracer TRACER = new ApacheHttpClientTracer();
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
|
||||
public class ContextScopePair {
|
||||
private final Context context;
|
||||
private final Scope scope;
|
||||
|
||||
public ContextScopePair(Context context, Scope scope) {
|
||||
this.context = context;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void closeScope() {
|
||||
scope.close();
|
||||
}
|
||||
}
|
|
@ -8,24 +8,24 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0;
|
|||
import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import java.io.IOException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.ResponseHandler;
|
||||
|
||||
public class WrappingStatusSettingResponseHandler implements ResponseHandler {
|
||||
final Span span;
|
||||
final Context context;
|
||||
final ResponseHandler handler;
|
||||
|
||||
public WrappingStatusSettingResponseHandler(Span span, ResponseHandler handler) {
|
||||
this.span = span;
|
||||
public WrappingStatusSettingResponseHandler(Context context, ResponseHandler handler) {
|
||||
this.context = context;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
|
||||
if (null != span) {
|
||||
tracer().onResponse(span, response);
|
||||
public Object handleResponse(HttpResponse response) throws IOException {
|
||||
if (context != null) {
|
||||
tracer().onResponse(Span.fromContext(context), response);
|
||||
}
|
||||
return handler.handleResponse(response);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.linecorp.armeria.common.HttpResponse;
|
|||
import com.linecorp.armeria.common.logging.RequestLogProperty;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -52,8 +53,9 @@ public class OpenTelemetryClient extends SimpleDecoratingHttpClient {
|
|||
long requestStartTimeMicros =
|
||||
ctx.log().ensureAvailable(RequestLogProperty.REQUEST_START_TIME).requestStartTimeMicros();
|
||||
long requestStartTimeNanos = TimeUnit.MICROSECONDS.toNanos(requestStartTimeMicros);
|
||||
Span span = clientTracer.startSpan(ctx, requestStartTimeNanos);
|
||||
Context context = clientTracer.startSpan(Context.current(), ctx, ctx, requestStartTimeNanos);
|
||||
|
||||
Span span = Span.fromContext(context);
|
||||
if (span.isRecording()) {
|
||||
ctx.log()
|
||||
.whenComplete()
|
||||
|
@ -64,14 +66,14 @@ public class OpenTelemetryClient extends SimpleDecoratingHttpClient {
|
|||
long requestEndTimeNanos = requestStartTimeNanos + log.responseDurationNanos();
|
||||
if (log.responseCause() != null) {
|
||||
clientTracer.endExceptionally(
|
||||
span, log, log.responseCause(), requestEndTimeNanos);
|
||||
context, log, log.responseCause(), requestEndTimeNanos);
|
||||
} else {
|
||||
clientTracer.end(span, log, requestEndTimeNanos);
|
||||
clientTracer.end(context, log, requestEndTimeNanos);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try (Scope ignored = clientTracer.startScope(span, ctx)) {
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
return unwrap().execute(ctx, req);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,32 +5,40 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.asynchttpclient;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.asynchttpclient.AsyncHttpClientTracer.tracer;
|
||||
|
||||
import com.ning.http.client.AsyncHandler;
|
||||
import com.ning.http.client.Request;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.Pair;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
public class RequestAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static Scope onEnter(
|
||||
@Advice.Argument(0) Request request, @Advice.Argument(1) AsyncHandler<?> handler) {
|
||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||
public static void onEnter(
|
||||
@Advice.Argument(0) Request request,
|
||||
@Advice.Argument(1) AsyncHandler<?> handler,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Span span = AsyncHttpClientTracer.tracer().startSpan(request);
|
||||
Context context = tracer().startSpan(parentContext, request, request);
|
||||
InstrumentationContext.get(AsyncHandler.class, Pair.class)
|
||||
.put(handler, Pair.of(parentContext, span));
|
||||
return AsyncHttpClientTracer.tracer().startScope(span, request);
|
||||
.put(handler, Pair.of(parentContext, context));
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void onExit(@Advice.Enter Scope scope) {
|
||||
// span closed in ClientResponseAdvice
|
||||
scope.close();
|
||||
public static void onExit(@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
}
|
||||
// span ended in ClientResponseAdvice
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ package io.opentelemetry.javaagent.instrumentation.asynchttpclient;
|
|||
import com.ning.http.client.AsyncCompletionHandler;
|
||||
import com.ning.http.client.AsyncHandler;
|
||||
import com.ning.http.client.Response;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
||||
|
@ -26,14 +25,13 @@ public class ResponseAdvice {
|
|||
// After response was handled by user provided handler.
|
||||
ContextStore<AsyncHandler, Pair> contextStore =
|
||||
InstrumentationContext.get(AsyncHandler.class, Pair.class);
|
||||
Pair<Context, Span> spanWithParent = contextStore.get(handler);
|
||||
if (null != spanWithParent) {
|
||||
contextStore.put(handler, null);
|
||||
Pair<Context, Context> parentAndChildContext = contextStore.get(handler);
|
||||
if (parentAndChildContext == null) {
|
||||
return null;
|
||||
}
|
||||
if (spanWithParent.hasRight()) {
|
||||
AsyncHttpClientTracer.tracer().end(spanWithParent.getRight(), response);
|
||||
}
|
||||
return spanWithParent.hasLeft() ? spanWithParent.getLeft().makeCurrent() : null;
|
||||
contextStore.put(handler, null);
|
||||
AsyncHttpClientTracer.tracer().end(parentAndChildContext.getRight(), response);
|
||||
return parentAndChildContext.getLeft().makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.SPAN_SCOPE_PAIR_CONTEXT_KEY;
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
|
@ -16,7 +16,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
|||
import com.amazonaws.AmazonClientException;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.handlers.RequestHandler2;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
@ -49,10 +48,10 @@ public class AwsHttpClientInstrumentation implements TypeInstrumentation {
|
|||
@Advice.Argument(value = 0, optional = true) Request<?> request,
|
||||
@Advice.Thrown Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY);
|
||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||
if (scope != null) {
|
||||
request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
tracer().endExceptionally(scope.getSpan(), throwable);
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
tracer().endExceptionally(scope.getContext(), throwable);
|
||||
scope.closeScope();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.amazonaws.AmazonWebServiceResponse;
|
|||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import java.net.URI;
|
||||
|
@ -39,8 +40,9 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
|
|||
return qualifiedOperation(awsServiceName, awsOperation);
|
||||
}
|
||||
|
||||
public Span startSpan(Request<?> request, RequestMeta requestMeta) {
|
||||
Span span = super.startSpan(request);
|
||||
public Context startSpan(Context parentContext, Request<?> request, RequestMeta requestMeta) {
|
||||
Context context = super.startSpan(parentContext, request, request);
|
||||
Span span = Span.fromContext(context);
|
||||
|
||||
String awsServiceName = request.getServiceName();
|
||||
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
|
||||
|
@ -58,7 +60,7 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
|
|||
span.setAttribute("aws.stream.name", requestMeta.getStreamName());
|
||||
span.setAttribute("aws.table.name", requestMeta.getTableName());
|
||||
}
|
||||
return span;
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
|
||||
public class ContextScopePair {
|
||||
private final Context context;
|
||||
private final Scope scope;
|
||||
|
||||
public ContextScopePair(Context context, Scope scope) {
|
||||
this.context = context;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void closeScope() {
|
||||
scope.close();
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.SPAN_SCOPE_PAIR_CONTEXT_KEY;
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
|
@ -14,7 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
|
||||
import com.amazonaws.Request;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
@ -45,10 +44,10 @@ public class RequestExecutorInstrumentation implements TypeInstrumentation {
|
|||
public static void methodExit(
|
||||
@Advice.FieldValue("request") Request<?> request, @Advice.Thrown Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY);
|
||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||
if (scope != null) {
|
||||
request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
tracer().endExceptionally(scope.getSpan(), throwable);
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
tracer().endExceptionally(scope.getContext(), throwable);
|
||||
scope.closeScope();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.handlers.HandlerContextKey;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
|
||||
import java.util.Objects;
|
||||
|
||||
public class RequestMeta {
|
||||
// Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context
|
||||
// safely.
|
||||
public static final HandlerContextKey<SpanWithScope> SPAN_SCOPE_PAIR_CONTEXT_KEY =
|
||||
new HandlerContextKey<>("io.opentelemetry.auto.SpanWithScope");
|
||||
public static final HandlerContextKey<ContextScopePair> CONTEXT_SCOPE_PAIR_CONTEXT_KEY =
|
||||
new HandlerContextKey<>(RequestMeta.class.getName() + ".ContextSpanPair");
|
||||
|
||||
private String bucketName;
|
||||
private String queueUrl;
|
||||
|
|
|
@ -6,16 +6,15 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.SPAN_SCOPE_PAIR_CONTEXT_KEY;
|
||||
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceRequest;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import com.amazonaws.handlers.RequestHandler2;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
|
||||
|
||||
/** Tracing Request Handler. */
|
||||
public class TracingRequestHandler extends RequestHandler2 {
|
||||
|
@ -30,28 +29,32 @@ public class TracingRequestHandler extends RequestHandler2 {
|
|||
public void beforeRequest(Request<?> request) {
|
||||
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
|
||||
RequestMeta requestMeta = contextStore.get(originalRequest);
|
||||
Span span = tracer().startSpan(request, requestMeta);
|
||||
Scope scope = tracer().startScope(span, request);
|
||||
request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, new SpanWithScope(span, scope));
|
||||
Context parentContext = Context.current();
|
||||
if (tracer().shouldStartSpan(parentContext)) {
|
||||
Context context = tracer().startSpan(parentContext, request, requestMeta);
|
||||
Scope scope = context.makeCurrent();
|
||||
request.addHandlerContext(
|
||||
CONTEXT_SCOPE_PAIR_CONTEXT_KEY, new ContextScopePair(context, scope));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterResponse(Request<?> request, Response<?> response) {
|
||||
SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY);
|
||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||
if (scope != null) {
|
||||
request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
scope.closeScope();
|
||||
tracer().end(scope.getSpan(), response);
|
||||
tracer().end(scope.getContext(), response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterError(Request<?> request, Response<?> response, Exception e) {
|
||||
SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY);
|
||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||
if (scope != null) {
|
||||
request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
scope.closeScope();
|
||||
tracer().endExceptionally(scope.getSpan(), response, e);
|
||||
tracer().endExceptionally(scope.getContext(), response, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,15 +58,6 @@ public class AwsSdk {
|
|||
return new TracingExecutionInterceptor(kind);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Span} stored in the {@link ExecutionAttributes}, or {@code null} if there is
|
||||
* no span set.
|
||||
*/
|
||||
public static Span getSpanFromAttributes(ExecutionAttributes attributes) {
|
||||
Context context = getContextFromAttributes(attributes);
|
||||
return context == null ? Span.getInvalid() : Span.fromContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Span} stored in the {@link ExecutionAttributes}, or {@code null} if there is
|
||||
* no span set.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||
|
||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getSpanFromAttributes;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getContextFromAttributes;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer.tracer;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.RequestType.ofSdkRequest;
|
||||
|
||||
|
@ -108,8 +108,9 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
@Override
|
||||
public void afterMarshalling(
|
||||
Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
|
||||
Span span = getSpanFromAttributes(executionAttributes);
|
||||
if (span.getSpanContext().isValid()) {
|
||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
||||
if (otelContext != null) {
|
||||
Span span = Span.fromContext(otelContext);
|
||||
tracer().onRequest(span, context.httpRequest());
|
||||
SdkRequestDecorator decorator = decorator(executionAttributes);
|
||||
if (decorator != null) {
|
||||
|
@ -145,12 +146,13 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
@Override
|
||||
public void afterExecution(
|
||||
Context.AfterExecution context, ExecutionAttributes executionAttributes) {
|
||||
Span span = getSpanFromAttributes(executionAttributes);
|
||||
if (span.getSpanContext().isValid()) {
|
||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
||||
if (otelContext != null) {
|
||||
clearAttributes(executionAttributes);
|
||||
Span span = Span.fromContext(otelContext);
|
||||
tracer().afterExecution(span, context.httpRequest());
|
||||
onSdkResponse(span, context.response());
|
||||
tracer().end(span, context.httpResponse());
|
||||
tracer().end(otelContext, context.httpResponse());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,10 +165,10 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
@Override
|
||||
public void onExecutionFailure(
|
||||
Context.FailedExecution context, ExecutionAttributes executionAttributes) {
|
||||
Span span = getSpanFromAttributes(executionAttributes);
|
||||
if (span.getSpanContext().isValid()) {
|
||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
||||
if (otelContext != null) {
|
||||
clearAttributes(executionAttributes);
|
||||
tracer().endExceptionally(span, context.exception());
|
||||
tracer().endExceptionally(otelContext, context.exception());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,30 +80,16 @@ class Elasticsearch6RestClientTest extends AgentTestRunner {
|
|||
result.status == "green"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
name "GET _cluster/health"
|
||||
kind CLIENT
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch"
|
||||
"${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health"
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name expectedOperationName("GET")
|
||||
kind CLIENT
|
||||
childOf span(0)
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
|
||||
"${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1"
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,6 @@ public class Elasticsearch5RestClientInstrumentationModule extends Instrumentati
|
|||
span = tracer().startSpan(null, method + " " + endpoint);
|
||||
scope = tracer().startScope(span);
|
||||
|
||||
tracer().onRequest(span, method, endpoint);
|
||||
responseListener = new RestResponseListener(responseListener, span);
|
||||
}
|
||||
|
||||
|
|
|
@ -84,30 +84,16 @@ class Elasticsearch5RestClientTest extends AgentTestRunner {
|
|||
result.status == "green"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
name "GET _cluster/health"
|
||||
kind CLIENT
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch"
|
||||
"${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health"
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name expectedOperationName("GET")
|
||||
kind CLIENT
|
||||
childOf span(0)
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200
|
||||
"${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1"
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,30 +85,16 @@ class Elasticsearch6RestClientTest extends AgentTestRunner {
|
|||
result.status == "green"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
name "GET _cluster/health"
|
||||
kind CLIENT
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch"
|
||||
"${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health"
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name expectedOperationName("GET")
|
||||
kind CLIENT
|
||||
childOf span(0)
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200
|
||||
"${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1"
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@ public class Elasticsearch6RestClientInstrumentationModule extends Instrumentati
|
|||
span = tracer().startSpan(null, request.getMethod() + " " + request.getEndpoint());
|
||||
scope = tracer().startScope(span);
|
||||
|
||||
tracer().onRequest(span, request.getMethod(), request.getEndpoint());
|
||||
responseListener = new RestResponseListener(responseListener, span);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,30 +80,16 @@ class Elasticsearch6RestClientTest extends AgentTestRunner {
|
|||
result.status == "green"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
name "GET _cluster/health"
|
||||
kind CLIENT
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch"
|
||||
"${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health"
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name expectedOperationName("GET")
|
||||
kind CLIENT
|
||||
childOf span(0)
|
||||
attributes {
|
||||
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
|
||||
"${SemanticAttributes.HTTP_URL.key()}" "_cluster/health"
|
||||
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
|
||||
"${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200
|
||||
"${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1"
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,6 @@ public class ElasticsearchRestClientTracer extends DatabaseClientTracer<Void, St
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
public Span onRequest(Span span, String method, String endpoint) {
|
||||
span.setAttribute(SemanticAttributes.HTTP_METHOD, method);
|
||||
span.setAttribute(SemanticAttributes.HTTP_URL, endpoint);
|
||||
return span;
|
||||
}
|
||||
|
||||
public Span onResponse(Span span, Response response) {
|
||||
if (response != null && response.getHost() != null) {
|
||||
NetPeerUtils.INSTANCE.setNetPeer(span, response.getHost().getHostName(), null);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.spanFromContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.googlehttpclient.GoogleHttpClientTracer.tracer;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
@ -17,13 +19,11 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.google.api.client.http.HttpRequest;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.util.HashMap;
|
||||
|
@ -82,21 +82,22 @@ public class GoogleHttpClientInstrumentationModule extends InstrumentationModule
|
|||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(
|
||||
@Advice.This HttpRequest request,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
||||
ContextStore<HttpRequest, Context> contextStore =
|
||||
InstrumentationContext.get(HttpRequest.class, Context.class);
|
||||
Context context = contextStore.get(request);
|
||||
context = contextStore.get(request);
|
||||
|
||||
if (context == null) {
|
||||
span = tracer().startSpan(request);
|
||||
scope = tracer().startScope(span, request.getHeaders());
|
||||
// TODO (trask) ideally we could pass current context into startScope to avoid extra lookup
|
||||
contextStore.put(request, Java8BytecodeBridge.currentContext());
|
||||
Context parentContext = currentContext();
|
||||
if (tracer().shouldStartSpan(parentContext)) {
|
||||
context = tracer().startSpan(parentContext, request, request.getHeaders());
|
||||
contextStore.put(request, context);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
} else {
|
||||
// span was created by GoogleHttpClientAsyncAdvice instrumentation below
|
||||
span = Java8BytecodeBridge.spanFromContext(context);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
}
|
||||
|
@ -105,20 +106,22 @@ public class GoogleHttpClientInstrumentationModule extends InstrumentationModule
|
|||
public static void methodExit(
|
||||
@Advice.Return HttpResponse response,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
|
||||
if (throwable == null) {
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
} else {
|
||||
tracer().endExceptionally(span, response, throwable);
|
||||
tracer().endExceptionally(context, response, throwable);
|
||||
}
|
||||
// If HttpRequest.setThrowExceptionOnExecuteError is set to false, there are no exceptions
|
||||
// for a failed request. Thus, check the response code
|
||||
if (response != null && !response.isSuccessStatusCode()) {
|
||||
span.setStatus(StatusCode.ERROR);
|
||||
spanFromContext(context).setStatus(StatusCode.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,28 +131,36 @@ public class GoogleHttpClientInstrumentationModule extends InstrumentationModule
|
|||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(
|
||||
@Advice.This HttpRequest request,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
span = tracer().startSpan(request);
|
||||
scope = tracer().startScope(span, request.getHeaders());
|
||||
context = tracer().startSpan(parentContext, request, request.getHeaders());
|
||||
|
||||
// propagating the context manually here so this instrumentation will work with and without
|
||||
// the executors instrumentation
|
||||
ContextStore<HttpRequest, Context> contextStore =
|
||||
InstrumentationContext.get(HttpRequest.class, Context.class);
|
||||
contextStore.put(request, Java8BytecodeBridge.currentContext());
|
||||
contextStore.put(request, context);
|
||||
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.httpurlconnection;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.httpurlconnection.HttpUrlConnectionTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
|
||||
import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf;
|
||||
|
@ -17,7 +18,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
||||
|
@ -79,7 +80,7 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul
|
|||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static HttpUrlState methodEnter(
|
||||
@Advice.This HttpURLConnection thiz,
|
||||
@Advice.This HttpURLConnection connection,
|
||||
@Advice.FieldValue("connected") boolean connected,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
||||
|
@ -90,22 +91,27 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul
|
|||
|
||||
ContextStore<HttpURLConnection, HttpUrlState> contextStore =
|
||||
InstrumentationContext.get(HttpURLConnection.class, HttpUrlState.class);
|
||||
HttpUrlState state = contextStore.putIfAbsent(thiz, HttpUrlState.FACTORY);
|
||||
HttpUrlState state = contextStore.putIfAbsent(connection, HttpUrlState::new);
|
||||
|
||||
synchronized (state) {
|
||||
if (!state.hasSpan() && !state.isFinished()) {
|
||||
Span span = state.start(thiz);
|
||||
if (!connected) {
|
||||
scope = tracer().startScope(span, thiz);
|
||||
if (!state.initialized) {
|
||||
Context parentContext = currentContext();
|
||||
if (tracer().shouldStartSpan(parentContext)) {
|
||||
state.context = tracer().startSpan(parentContext, connection, connection);
|
||||
if (!connected) {
|
||||
scope = state.context.makeCurrent();
|
||||
}
|
||||
}
|
||||
state.initialized = true;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter HttpUrlState state,
|
||||
@Advice.This HttpURLConnection connection,
|
||||
@Advice.FieldValue("responseCode") int responseCode,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Origin("#m") String methodName,
|
||||
|
@ -120,62 +126,28 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul
|
|||
CallDepthThreadLocalMap.reset(HttpURLConnection.class);
|
||||
|
||||
synchronized (state) {
|
||||
if (state.hasSpan() && !state.isFinished()) {
|
||||
if (state.context != null && !state.finished) {
|
||||
if (throwable != null) {
|
||||
state.finishSpan(throwable);
|
||||
tracer().endExceptionally(state.context, throwable);
|
||||
state.finished = true;
|
||||
} else if ("getInputStream".equals(methodName)) {
|
||||
state.finishSpan(responseCode);
|
||||
// responseCode field is sometimes not populated.
|
||||
// We can't call getResponseCode() due to some unwanted side-effects
|
||||
// (e.g. breaks getOutputStream).
|
||||
if (responseCode > 0) {
|
||||
tracer().end(state.context, new HttpUrlResponse(connection, responseCode));
|
||||
state.finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// state is always accessed under synchronized block
|
||||
public static class HttpUrlState {
|
||||
|
||||
public static final ContextStore.Factory<HttpUrlState> FACTORY =
|
||||
new ContextStore.Factory<HttpUrlState>() {
|
||||
@Override
|
||||
public HttpUrlState create() {
|
||||
return new HttpUrlState();
|
||||
}
|
||||
};
|
||||
|
||||
private volatile Span span = null;
|
||||
private volatile boolean finished = false;
|
||||
|
||||
public Span start(HttpURLConnection connection) {
|
||||
span = tracer().startSpan(connection);
|
||||
return span;
|
||||
}
|
||||
|
||||
public boolean hasSpan() {
|
||||
return span != null;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
public void finishSpan(Throwable throwable) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
span = null;
|
||||
finished = true;
|
||||
}
|
||||
|
||||
public void finishSpan(int responseCode) {
|
||||
/*
|
||||
* responseCode field is sometimes not populated.
|
||||
* We can't call getResponseCode() due to some unwanted side-effects
|
||||
* (e.g. breaks getOutputStream).
|
||||
*/
|
||||
if (responseCode > 0) {
|
||||
// Need to explicitly cast to boxed type to make sure correct method is called.
|
||||
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/946
|
||||
tracer().end(span, (Integer) responseCode);
|
||||
span = null;
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
public boolean initialized;
|
||||
public Context context;
|
||||
public boolean finished;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.net.URI;
|
|||
import java.net.URISyntaxException;
|
||||
|
||||
public class HttpUrlConnectionTracer
|
||||
extends HttpClientTracer<HttpURLConnection, HttpURLConnection, Integer> {
|
||||
extends HttpClientTracer<HttpURLConnection, HttpURLConnection, HttpUrlResponse> {
|
||||
|
||||
private static final HttpUrlConnectionTracer TRACER = new HttpUrlConnectionTracer();
|
||||
|
||||
|
@ -33,8 +33,8 @@ public class HttpUrlConnectionTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Integer status(Integer status) {
|
||||
return status;
|
||||
protected Integer status(HttpUrlResponse response) {
|
||||
return response.status();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,8 +43,8 @@ public class HttpUrlConnectionTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String responseHeader(Integer integer, String name) {
|
||||
return null;
|
||||
protected String responseHeader(HttpUrlResponse response, String name) {
|
||||
return response.header(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.httpurlconnection;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
public class HttpUrlResponse {
|
||||
private final HttpURLConnection connection;
|
||||
private final int resolvedResponseCode;
|
||||
|
||||
public HttpUrlResponse(HttpURLConnection connection, int resolvedResponseCode) {
|
||||
this.connection = connection;
|
||||
this.resolvedResponseCode = resolvedResponseCode;
|
||||
}
|
||||
|
||||
int status() {
|
||||
return resolvedResponseCode;
|
||||
}
|
||||
|
||||
String header(String name) {
|
||||
return connection.getHeaderField(name);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.httpclient;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.httpclient.JdkHttpClientTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
|
||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
|
||||
|
@ -16,9 +17,8 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
|
@ -72,34 +72,32 @@ public class HttpClientInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(value = 0) HttpRequest httpRequest,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
|
||||
callDepth = tracer().getCallDepth();
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
span = tracer().startSpan(httpRequest);
|
||||
if (span.getSpanContext().isValid()) {
|
||||
scope = tracer().startScope(span, httpRequest);
|
||||
}
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
context = tracer().startSpan(parentContext, httpRequest, httpRequest);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Return HttpResponse<?> result,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callDepth.decrementAndGet() == 0 && scope != null) {
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
tracer().end(span, result);
|
||||
} else {
|
||||
tracer().endExceptionally(span, result, throwable);
|
||||
}
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
tracer().end(context, result);
|
||||
} else {
|
||||
tracer().endExceptionally(context, result, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,34 +107,32 @@ public class HttpClientInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(
|
||||
@Advice.Argument(value = 0) HttpRequest httpRequest,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
|
||||
callDepth = tracer().getCallDepth();
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
span = tracer().startSpan(httpRequest);
|
||||
if (span.getSpanContext().isValid()) {
|
||||
scope = tracer().startScope(span, httpRequest);
|
||||
}
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
context = tracer().startSpan(parentContext, httpRequest, httpRequest);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Return(readOnly = false) CompletableFuture<HttpResponse<?>> future,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callDepth.decrementAndGet() == 0 && scope != null) {
|
||||
scope.close();
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, null, throwable);
|
||||
} else {
|
||||
future = future.whenComplete(new ResponseConsumer(span));
|
||||
}
|
||||
scope.close();
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(context, null, throwable);
|
||||
} else {
|
||||
future = future.whenComplete(new ResponseConsumer(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,7 @@ import io.opentelemetry.api.trace.attributes.SemanticAttributes;
|
|||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.net.http.HttpHeaders;
|
||||
import java.net.http.HttpRequest;
|
||||
|
@ -33,10 +30,6 @@ public class JdkHttpClientTracer
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
public Depth getCallDepth() {
|
||||
return CallDepthThreadLocalMap.getCallDepth(HttpClient.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.javaagent.java-httpclient";
|
||||
|
|
|
@ -7,23 +7,23 @@ package io.opentelemetry.javaagent.instrumentation.httpclient;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.httpclient.JdkHttpClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class ResponseConsumer implements BiConsumer<HttpResponse<?>, Throwable> {
|
||||
private final Span span;
|
||||
private final Context context;
|
||||
|
||||
public ResponseConsumer(Span span) {
|
||||
this.span = span;
|
||||
public ResponseConsumer(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpResponse<?> httpResponse, Throwable throwable) {
|
||||
if (throwable == null) {
|
||||
tracer().end(span, httpResponse);
|
||||
tracer().end(context, httpResponse);
|
||||
} else {
|
||||
tracer().endExceptionally(span, httpResponse, throwable);
|
||||
tracer().endExceptionally(context, httpResponse, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.tracer.HttpServerTracer.CONTEXT_ATTRIBUTE;
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1.JaxRsClientV1Tracer.tracer;
|
||||
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
|
||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
|
||||
|
@ -17,10 +18,9 @@ import static net.bytebuddy.matcher.ElementMatchers.returns;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.sun.jersey.api.client.ClientHandler;
|
||||
import com.sun.jersey.api.client.ClientRequest;
|
||||
import com.sun.jersey.api.client.ClientResponse;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
|
@ -69,15 +69,14 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
|||
@Advice.OnMethodEnter
|
||||
public static void onEnter(
|
||||
@Advice.Argument(0) ClientRequest request,
|
||||
@Advice.This ClientHandler thisObj,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
||||
// WARNING: this might be a chain...so we only have to trace the first in the chain.
|
||||
boolean isRootClientHandler = null == request.getProperties().get(CONTEXT_ATTRIBUTE);
|
||||
if (isRootClientHandler) {
|
||||
span = tracer().startSpan(request);
|
||||
scope = tracer().startScope(span, request);
|
||||
Context parentContext = currentContext();
|
||||
if (isRootClientHandler && tracer().shouldStartSpan(parentContext)) {
|
||||
context = tracer().startSpan(parentContext, request, request);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,16 +84,17 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
|||
public static void onExit(
|
||||
@Advice.Return ClientResponse response,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
} else {
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JaxRsClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.Context;
|
||||
import javax.annotation.Priority;
|
||||
import javax.ws.rs.Priorities;
|
||||
import javax.ws.rs.client.ClientRequestContext;
|
||||
|
@ -18,23 +17,23 @@ import javax.ws.rs.client.ClientResponseFilter;
|
|||
|
||||
@Priority(Priorities.HEADER_DECORATOR)
|
||||
public class ClientTracingFilter implements ClientRequestFilter, ClientResponseFilter {
|
||||
public static final String SPAN_PROPERTY_NAME = "io.opentelemetry.auto.jax-rs-client.span";
|
||||
public static final String CONTEXT_PROPERTY_NAME = "io.opentelemetry.auto.jax-rs-client.context";
|
||||
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext) {
|
||||
Span span = tracer().startSpan(requestContext);
|
||||
// TODO (trask) expose inject separate from startScope, e.g. for async cases
|
||||
Scope scope = tracer().startScope(span, requestContext);
|
||||
scope.close();
|
||||
requestContext.setProperty(SPAN_PROPERTY_NAME, span);
|
||||
Context parentContext = Context.current();
|
||||
if (tracer().shouldStartSpan(parentContext)) {
|
||||
Context context = tracer().startSpan(parentContext, requestContext, requestContext);
|
||||
requestContext.setProperty(CONTEXT_PROPERTY_NAME, context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) {
|
||||
Object spanObj = requestContext.getProperty(SPAN_PROPERTY_NAME);
|
||||
if (spanObj instanceof Span) {
|
||||
Span span = (Span) spanObj;
|
||||
tracer().end(span, responseContext);
|
||||
Object contextObj = requestContext.getProperty(CONTEXT_PROPERTY_NAME);
|
||||
if (contextObj instanceof Context) {
|
||||
Context context = (Context) contextObj;
|
||||
tracer().end(context, responseContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.util.Collections;
|
||||
|
@ -71,9 +71,9 @@ public class JerseyClientInstrumentationModule extends InstrumentationModule {
|
|||
@Advice.FieldValue("requestContext") ClientRequest context,
|
||||
@Advice.Thrown Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
Object prop = context.getProperty(ClientTracingFilter.SPAN_PROPERTY_NAME);
|
||||
if (prop instanceof Span) {
|
||||
tracer().endExceptionally((Span) prop, throwable);
|
||||
Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME);
|
||||
if (prop instanceof Context) {
|
||||
tracer().endExceptionally((Context) prop, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JaxRsClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -44,9 +44,9 @@ public class WrappedFuture<T> implements Future<T> {
|
|||
try {
|
||||
return wrapped.get();
|
||||
} catch (ExecutionException e) {
|
||||
Object prop = context.getProperty(ClientTracingFilter.SPAN_PROPERTY_NAME);
|
||||
if (prop instanceof Span) {
|
||||
tracer().endExceptionally((Span) prop, e.getCause());
|
||||
Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME);
|
||||
if (prop instanceof Context) {
|
||||
tracer().endExceptionally((Context) prop, e.getCause());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
@ -58,9 +58,9 @@ public class WrappedFuture<T> implements Future<T> {
|
|||
try {
|
||||
return wrapped.get(timeout, unit);
|
||||
} catch (ExecutionException e) {
|
||||
Object prop = context.getProperty(ClientTracingFilter.SPAN_PROPERTY_NAME);
|
||||
if (prop instanceof Span) {
|
||||
tracer().endExceptionally((Span) prop, e.getCause());
|
||||
Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME);
|
||||
if (prop instanceof Context) {
|
||||
tracer().endExceptionally((Context) prop, e.getCause());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.ResteasyClientTracer.tracer;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
@ -14,7 +15,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
|
@ -67,25 +68,30 @@ public class ResteasyClientInstrumentationModule extends InstrumentationModule {
|
|||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(
|
||||
@Advice.This ClientInvocation invocation,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
span = tracer().startSpan(invocation);
|
||||
scope = tracer().startScope(span, invocation);
|
||||
Context parentContext = currentContext();
|
||||
if (tracer().shouldStartSpan(parentContext)) {
|
||||
context = tracer().startSpan(parentContext, invocation, invocation);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Return Response response,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
} else {
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcUtils.normaliz
|
|||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementInfo;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.sql.Connection;
|
||||
|
@ -62,7 +62,7 @@ public class JdbcTracer extends DatabaseClientTracer<DbInfo, SqlStatementInfo> {
|
|||
return info.getShortUrl();
|
||||
}
|
||||
|
||||
public Depth getCallDepth() {
|
||||
public CallDepth getCallDepth() {
|
||||
return CallDepthThreadLocalMap.getCallDepth(Statement.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.util.Map;
|
||||
|
@ -51,7 +51,7 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation {
|
|||
@Advice.This PreparedStatement statement,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
|
||||
callDepth = tracer().getCallDepth();
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
|
@ -67,7 +67,7 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation {
|
|||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
if (callDepth.decrementAndGet() == 0 && scope != null) {
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
|
|
|
@ -16,7 +16,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
import java.sql.Statement;
|
||||
import java.util.Map;
|
||||
|
@ -52,7 +52,7 @@ public class StatementInstrumentation implements TypeInstrumentation {
|
|||
@Advice.This Statement statement,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
|
||||
callDepth = tracer().getCallDepth();
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
|
@ -68,7 +68,7 @@ public class StatementInstrumentation implements TypeInstrumentation {
|
|||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
if (callDepth.decrementAndGet() == 0 && scope != null) {
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.khttp;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.khttp.KHttpHeadersInjectAdapter.asWritable;
|
||||
import static io.opentelemetry.javaagent.instrumentation.khttp.KHttpTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import java.util.Map;
|
||||
import khttp.responses.Response;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
@ -22,34 +22,33 @@ public class KHttpAdvice {
|
|||
@Advice.Argument(value = 0) String method,
|
||||
@Advice.Argument(value = 1) String uri,
|
||||
@Advice.Argument(value = 2, readOnly = false) Map<String, String> headers,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
|
||||
callDepth = tracer().getCallDepth();
|
||||
if (callDepth.getAndIncrement() == 0) {
|
||||
span = tracer().startSpan(new RequestWrapper(method, uri, headers));
|
||||
if (span.getSpanContext().isValid()) {
|
||||
headers = asWritable(headers);
|
||||
scope = tracer().startScope(span, headers);
|
||||
}
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
headers = asWritable(headers);
|
||||
context = tracer().startSpan(parentContext, new RequestWrapper(method, uri, headers), headers);
|
||||
scope = context.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Return Response response,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
if (callDepth.decrementAndGet() == 0 && scope != null) {
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
tracer().end(span, response);
|
||||
} else {
|
||||
tracer().endExceptionally(span, response, throwable);
|
||||
}
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.close();
|
||||
if (throwable == null) {
|
||||
tracer().end(context, response);
|
||||
} else {
|
||||
tracer().endExceptionally(context, response, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,9 @@ import static io.opentelemetry.javaagent.instrumentation.khttp.KHttpHeadersInjec
|
|||
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Map;
|
||||
import khttp.KHttp;
|
||||
import khttp.responses.Response;
|
||||
|
||||
public class KHttpTracer extends HttpClientTracer<RequestWrapper, Map<String, String>, Response> {
|
||||
|
@ -24,10 +21,6 @@ public class KHttpTracer extends HttpClientTracer<RequestWrapper, Map<String, St
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
public Depth getCallDepth() {
|
||||
return CallDepthThreadLocalMap.getCallDepth(KHttp.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(RequestWrapper requestWrapper) {
|
||||
return requestWrapper.method;
|
||||
|
|
|
@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.kubernetesclient;
|
|||
|
||||
import static io.opentelemetry.api.trace.Span.Kind.CLIENT;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import java.net.URI;
|
||||
|
@ -21,6 +23,27 @@ public class KubernetesClientTracer extends HttpClientTracer<Request, Request, R
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to generate an acceptable CLIENT span (operation) name based on a given
|
||||
* KubernetesRequestDigest.
|
||||
*/
|
||||
public Context startSpan(Context parentContext, Request request) {
|
||||
KubernetesRequestDigest digest = KubernetesRequestDigest.parse(request);
|
||||
Span span =
|
||||
tracer
|
||||
.spanBuilder(digest.toString())
|
||||
.setSpanKind(CLIENT)
|
||||
.setParent(parentContext)
|
||||
.setAttribute("namespace", digest.getResourceMeta().getNamespace())
|
||||
.setAttribute("name", digest.getResourceMeta().getName())
|
||||
.startSpan();
|
||||
Context context = parentContext.with(span).with(CONTEXT_CLIENT_SPAN_KEY, span);
|
||||
OpenTelemetry.getGlobalPropagators()
|
||||
.getTextMapPropagator()
|
||||
.inject(context, request, getSetter());
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(Request httpRequest) {
|
||||
return httpRequest.method();
|
||||
|
@ -62,17 +85,4 @@ public class KubernetesClientTracer extends HttpClientTracer<Request, Request, R
|
|||
protected Span onRequest(Span span, Request request) {
|
||||
return super.onRequest(span, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to generate an acceptable CLIENT span (operation) name based on a given
|
||||
* KubernetesRequestDigest.
|
||||
*/
|
||||
public Span startSpan(KubernetesRequestDigest digest) {
|
||||
return tracer
|
||||
.spanBuilder(digest.toString())
|
||||
.setSpanKind(CLIENT)
|
||||
.setAttribute("namespace", digest.getResourceMeta().getNamespace())
|
||||
.setAttribute("name", digest.getResourceMeta().getName())
|
||||
.startSpan();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,22 +19,18 @@ public class TracingInterceptor implements Interceptor {
|
|||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
|
||||
KubernetesRequestDigest digest = KubernetesRequestDigest.parse(chain.request());
|
||||
|
||||
Span span = tracer().startSpan(digest);
|
||||
tracer().onRequest(span, chain.request());
|
||||
|
||||
Context context = Context.current().with(span);
|
||||
Context context = tracer().startSpan(Context.current(), chain.request());
|
||||
tracer().onRequest(Span.fromContext(context), chain.request());
|
||||
|
||||
Response response;
|
||||
try (Scope scope = context.makeCurrent()) {
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
response = chain.proceed(chain.request());
|
||||
} catch (Exception e) {
|
||||
tracer().endExceptionally(span, e);
|
||||
tracer().endExceptionally(context, e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.netty.v3_8;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
||||
import java.util.Objects;
|
||||
|
@ -21,7 +20,6 @@ public class ChannelTraceContext {
|
|||
}
|
||||
|
||||
private Context connectionContext;
|
||||
private Span clientSpan;
|
||||
private Context clientParentContext;
|
||||
private Context context;
|
||||
|
||||
|
@ -33,14 +31,6 @@ public class ChannelTraceContext {
|
|||
this.connectionContext = connectionContinuation;
|
||||
}
|
||||
|
||||
public Span getClientSpan() {
|
||||
return clientSpan;
|
||||
}
|
||||
|
||||
public void setClientSpan(Span clientSpan) {
|
||||
this.clientSpan = clientSpan;
|
||||
}
|
||||
|
||||
public Context getClientParentContext() {
|
||||
return clientParentContext;
|
||||
}
|
||||
|
@ -67,13 +57,12 @@ public class ChannelTraceContext {
|
|||
}
|
||||
ChannelTraceContext other = (ChannelTraceContext) obj;
|
||||
return Objects.equals(connectionContext, other.connectionContext)
|
||||
&& Objects.equals(clientSpan, other.clientSpan)
|
||||
&& Objects.equals(clientParentContext, other.clientParentContext)
|
||||
&& Objects.equals(context, other.context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(connectionContext, clientSpan, clientParentContext, context);
|
||||
return Objects.hash(connectionContext, clientParentContext, context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,30 +38,33 @@ public class HttpClientRequestTracingHandler extends SimpleChannelDownstreamHand
|
|||
ChannelTraceContext channelTraceContext =
|
||||
contextStore.putIfAbsent(ctx.getChannel(), ChannelTraceContext.Factory.INSTANCE);
|
||||
|
||||
// TODO pass Context into Tracer.startSpan() and then don't need this scoping
|
||||
Scope parentScope = null;
|
||||
Context parentContext = channelTraceContext.getConnectionContext();
|
||||
if (parentContext != null) {
|
||||
parentScope = parentContext.makeCurrent();
|
||||
channelTraceContext.setConnectionContext(null);
|
||||
} else {
|
||||
parentContext = Context.current();
|
||||
}
|
||||
channelTraceContext.setClientParentContext(Context.current());
|
||||
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
ctx.sendDownstream(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
channelTraceContext.setClientParentContext(parentContext);
|
||||
|
||||
HttpRequest request = (HttpRequest) msg.getMessage();
|
||||
|
||||
Span span = tracer().startSpan(request);
|
||||
NetPeerUtils.INSTANCE.setNetPeer(span, (InetSocketAddress) ctx.getChannel().getRemoteAddress());
|
||||
channelTraceContext.setClientSpan(span);
|
||||
Context context = tracer().startSpan(parentContext, request, request.headers());
|
||||
// TODO (trask) move this setNetPeer() call into the Tracer
|
||||
NetPeerUtils.INSTANCE.setNetPeer(
|
||||
Span.fromContext(context), (InetSocketAddress) ctx.getChannel().getRemoteAddress());
|
||||
channelTraceContext.setContext(context);
|
||||
|
||||
try (Scope ignored = tracer().startScope(span, request.headers())) {
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
ctx.sendDownstream(msg);
|
||||
} catch (Throwable throwable) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
throw throwable;
|
||||
} finally {
|
||||
if (parentScope != null) {
|
||||
parentScope.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.netty.v3_8.client;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.NettyHttpClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
|
||||
|
@ -32,12 +31,12 @@ public class HttpClientResponseTracingHandler extends SimpleChannelUpstreamHandl
|
|||
contextStore.putIfAbsent(ctx.getChannel(), ChannelTraceContext.Factory.INSTANCE);
|
||||
|
||||
Context parentContext = channelTraceContext.getClientParentContext();
|
||||
Span span = channelTraceContext.getClientSpan();
|
||||
Context context = channelTraceContext.getContext();
|
||||
|
||||
boolean finishSpan = msg.getMessage() instanceof HttpResponse;
|
||||
|
||||
if (span != null && finishSpan) {
|
||||
tracer().end(span, (HttpResponse) msg.getMessage());
|
||||
if (context != null && finishSpan) {
|
||||
tracer().end(context, (HttpResponse) msg.getMessage());
|
||||
}
|
||||
|
||||
// We want the callback in the scope of the parent, not the client span
|
||||
|
|
|
@ -8,9 +8,6 @@ package io.opentelemetry.javaagent.instrumentation.netty.v3_8.client;
|
|||
import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.client.NettyResponseInjectAdapter.SETTER;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.HOST;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import java.net.URI;
|
||||
|
@ -28,20 +25,6 @@ public class NettyHttpClientTracer
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope startScope(Span span, HttpHeaders headers) {
|
||||
if (!headers.contains("amz-sdk-invocation-id")) {
|
||||
return super.startScope(span, headers);
|
||||
} else {
|
||||
// TODO (trask) if we move injection up to aws-sdk layer, and start suppressing nested netty
|
||||
// spans, do we still need this condition?
|
||||
// AWS calls are often signed, so we can't add headers without breaking the signature.
|
||||
Context context = Context.current().with(span);
|
||||
context = context.with(CONTEXT_CLIENT_SPAN_KEY, span);
|
||||
return context.makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(HttpRequest httpRequest) {
|
||||
return httpRequest.getMethod().getName();
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.netty.v4_0;
|
||||
|
||||
import io.netty.util.AttributeKey;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.WeakMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -31,7 +30,7 @@ public class AttributeKeys {
|
|||
public static final AttributeKey<Context> SERVER_SPAN =
|
||||
attributeKey(AttributeKeys.class.getName() + ".server-span");
|
||||
|
||||
public static final AttributeKey<Span> CLIENT_SPAN =
|
||||
public static final AttributeKey<Context> CLIENT_SPAN =
|
||||
attributeKey(AttributeKeys.class.getName() + ".client-span");
|
||||
|
||||
public static final AttributeKey<Context> CLIENT_PARENT_CONTEXT =
|
||||
|
|
|
@ -27,30 +27,31 @@ public class HttpClientRequestTracingHandler extends ChannelOutboundHandlerAdapt
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO pass Context into Tracer.startSpan() and then don't need this scoping
|
||||
Scope parentScope = null;
|
||||
Context parentContext = ctx.channel().attr(AttributeKeys.CONNECT_CONTEXT).getAndRemove();
|
||||
if (parentContext != null) {
|
||||
parentScope = parentContext.makeCurrent();
|
||||
if (parentContext == null) {
|
||||
parentContext = Context.current();
|
||||
}
|
||||
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
ctx.write(msg, prm);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpRequest request = (HttpRequest) msg;
|
||||
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(Context.current());
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(parentContext);
|
||||
|
||||
Span span = tracer().startSpan(request);
|
||||
NetPeerUtils.INSTANCE.setNetPeer(span, (InetSocketAddress) ctx.channel().remoteAddress());
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(span);
|
||||
Context context = tracer().startSpan(parentContext, request, request.headers());
|
||||
// TODO (trask) move this setNetPeer() call into the Tracer
|
||||
NetPeerUtils.INSTANCE.setNetPeer(
|
||||
Span.fromContext(context), (InetSocketAddress) ctx.channel().remoteAddress());
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(context);
|
||||
|
||||
try (Scope scope = tracer().startScope(span, request.headers())) {
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
ctx.write(msg, prm);
|
||||
} catch (Throwable throwable) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
throw throwable;
|
||||
} finally {
|
||||
if (null != parentScope) {
|
||||
parentScope.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import io.netty.channel.ChannelHandlerContext;
|
|||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.util.Attribute;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.v4_0.AttributeKeys;
|
||||
|
@ -22,12 +21,12 @@ public class HttpClientResponseTracingHandler extends ChannelInboundHandlerAdapt
|
|||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
Attribute<Context> parentAttr = ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT);
|
||||
Context parentContext = parentAttr.get();
|
||||
Span span = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get();
|
||||
Context context = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get();
|
||||
|
||||
boolean finishSpan = msg instanceof HttpResponse;
|
||||
|
||||
if (span != null && finishSpan) {
|
||||
tracer().end(span, (HttpResponse) msg);
|
||||
if (context != null && finishSpan) {
|
||||
tracer().end(context, (HttpResponse) msg);
|
||||
}
|
||||
|
||||
// We want the callback in the scope of the parent, not the client span
|
||||
|
|
|
@ -11,9 +11,6 @@ import static io.opentelemetry.javaagent.instrumentation.netty.v4_0.client.Netty
|
|||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import java.net.URI;
|
||||
|
@ -28,20 +25,6 @@ public class NettyHttpClientTracer
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope startScope(Span span, HttpHeaders headers) {
|
||||
if (!headers.contains("amz-sdk-invocation-id")) {
|
||||
return super.startScope(span, headers);
|
||||
} else {
|
||||
// TODO (trask) if we move injection up to aws-sdk layer, and start suppressing nested netty
|
||||
// spans, do we still need this condition?
|
||||
// AWS calls are often signed, so we can't add headers without breaking the signature.
|
||||
Context context = Context.current().with(span);
|
||||
context = context.with(CONTEXT_CLIENT_SPAN_KEY, span);
|
||||
return context.makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(HttpRequest httpRequest) {
|
||||
return httpRequest.getMethod().name();
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.netty.v4_1;
|
||||
|
||||
import io.netty.util.AttributeKey;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
|
||||
public class AttributeKeys {
|
||||
|
@ -20,7 +19,7 @@ public class AttributeKeys {
|
|||
public static final AttributeKey<Context> SERVER_SPAN =
|
||||
AttributeKey.valueOf(AttributeKeys.class, "server-span");
|
||||
|
||||
public static final AttributeKey<Span> CLIENT_SPAN =
|
||||
public static final AttributeKey<Context> CLIENT_SPAN =
|
||||
AttributeKey.valueOf(AttributeKeys.class, "client-span");
|
||||
|
||||
public static final AttributeKey<Context> CLIENT_PARENT_CONTEXT =
|
||||
|
|
|
@ -26,31 +26,32 @@ public class HttpClientRequestTracingHandler extends ChannelOutboundHandlerAdapt
|
|||
ctx.write(msg, prm);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO pass Context into Tracer.startSpan() and then don't need this scoping
|
||||
Scope parentScope = null;
|
||||
Context parentContext = ctx.channel().attr(AttributeKeys.CONNECT_CONTEXT).getAndRemove();
|
||||
if (parentContext != null) {
|
||||
parentScope = parentContext.makeCurrent();
|
||||
}
|
||||
|
||||
HttpRequest request = (HttpRequest) msg;
|
||||
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(Context.current());
|
||||
Context parentContext = ctx.channel().attr(AttributeKeys.CONNECT_CONTEXT).getAndRemove();
|
||||
if (parentContext == null) {
|
||||
parentContext = Context.current();
|
||||
}
|
||||
|
||||
Span span = tracer().startSpan(request);
|
||||
NetPeerUtils.INSTANCE.setNetPeer(span, (InetSocketAddress) ctx.channel().remoteAddress());
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(span);
|
||||
|
||||
try (Scope ignored = tracer().startScope(span, request.headers())) {
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
ctx.write(msg, prm);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(parentContext);
|
||||
|
||||
Context context = tracer().startSpan(parentContext, request, request.headers());
|
||||
// TODO (trask) move this setNetPeer() call into the Tracer
|
||||
NetPeerUtils.INSTANCE.setNetPeer(
|
||||
Span.fromContext(context), (InetSocketAddress) ctx.channel().remoteAddress());
|
||||
ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(context);
|
||||
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
ctx.write(msg, prm);
|
||||
// span is ended normally in HttpClientResponseTracingHandler
|
||||
} catch (Throwable throwable) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
throw throwable;
|
||||
} finally {
|
||||
if (null != parentScope) {
|
||||
parentScope.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import io.netty.channel.ChannelHandlerContext;
|
|||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.util.Attribute;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.v4_1.AttributeKeys;
|
||||
|
@ -22,12 +21,12 @@ public class HttpClientResponseTracingHandler extends ChannelInboundHandlerAdapt
|
|||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
Attribute<Context> parentAttr = ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT);
|
||||
Context parentContext = parentAttr.get();
|
||||
Span span = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get();
|
||||
Context context = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get();
|
||||
|
||||
boolean finishSpan = msg instanceof HttpResponse;
|
||||
|
||||
if (span != null && finishSpan) {
|
||||
tracer().end(span, (HttpResponse) msg);
|
||||
if (context != null && finishSpan) {
|
||||
tracer().end(context, (HttpResponse) msg);
|
||||
}
|
||||
|
||||
// We want the callback in the scope of the parent, not the client span
|
||||
|
|
|
@ -10,24 +10,29 @@ import static io.opentelemetry.javaagent.instrumentation.okhttp.v2_2.OkHttpClien
|
|||
import com.squareup.okhttp.Interceptor;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TracingInterceptor implements Interceptor {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Span span = tracer().startSpan(chain.request());
|
||||
Context parentContext = Context.current();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return chain.proceed(chain.request());
|
||||
}
|
||||
|
||||
Request.Builder requestBuilder = chain.request().newBuilder();
|
||||
Context context = tracer().startSpan(parentContext, chain.request(), requestBuilder);
|
||||
|
||||
Response response;
|
||||
try (Scope scope = tracer().startScope(span, requestBuilder)) {
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
response = chain.proceed(requestBuilder.build());
|
||||
} catch (Exception e) {
|
||||
tracer().endExceptionally(span, e);
|
||||
tracer().endExceptionally(context, e);
|
||||
throw e;
|
||||
}
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.okhttp.v3_0;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.okhttp.v3_0.OkHttpClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
import okhttp3.Interceptor;
|
||||
|
@ -18,17 +18,22 @@ public class TracingInterceptor implements Interceptor {
|
|||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Span span = tracer().startSpan(chain.request());
|
||||
Context parentContext = Context.current();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return chain.proceed(chain.request());
|
||||
}
|
||||
|
||||
Request.Builder requestBuilder = chain.request().newBuilder();
|
||||
Context context = tracer().startSpan(parentContext, chain.request(), requestBuilder);
|
||||
|
||||
Response response;
|
||||
Request.Builder requestBuilder = chain.request().newBuilder();
|
||||
try (Scope ignored = tracer().startScope(span, requestBuilder)) {
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
response = chain.proceed(requestBuilder.build());
|
||||
} catch (Exception e) {
|
||||
tracer().endExceptionally(span, e);
|
||||
tracer().endExceptionally(context, e);
|
||||
throw e;
|
||||
}
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.playws.v1_0;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import play.shaded.ahc.org.asynchttpclient.AsyncHandler;
|
||||
|
@ -18,15 +17,15 @@ import play.shaded.ahc.org.asynchttpclient.Response;
|
|||
|
||||
public class AsyncHandlerWrapper implements AsyncHandler {
|
||||
private final AsyncHandler delegate;
|
||||
private final Span span;
|
||||
private final Context invocationContext;
|
||||
private final Context context;
|
||||
private final Context parentContext;
|
||||
|
||||
private final Response.ResponseBuilder builder = new Response.ResponseBuilder();
|
||||
|
||||
public AsyncHandlerWrapper(AsyncHandler delegate, Span span, Context invocationContext) {
|
||||
public AsyncHandlerWrapper(AsyncHandler delegate, Context context, Context parentContext) {
|
||||
this.delegate = delegate;
|
||||
this.span = span;
|
||||
this.invocationContext = invocationContext;
|
||||
this.context = context;
|
||||
this.parentContext = parentContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,20 +49,18 @@ public class AsyncHandlerWrapper implements AsyncHandler {
|
|||
|
||||
@Override
|
||||
public Object onCompleted() throws Exception {
|
||||
Response response = builder.build();
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, builder.build());
|
||||
|
||||
try (Scope scope = invocationContext.makeCurrent()) {
|
||||
try (Scope scope = parentContext.makeCurrent()) {
|
||||
return delegate.onCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onThrowable(Throwable throwable) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
span.end();
|
||||
tracer().endExceptionally(context, throwable);
|
||||
|
||||
try (Scope scope = invocationContext.makeCurrent()) {
|
||||
try (Scope scope = parentContext.makeCurrent()) {
|
||||
delegate.onThrowable(throwable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.playws.v1_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
|
@ -39,32 +38,38 @@ public class PlayWsInstrumentationModule extends InstrumentationModule {
|
|||
public static void methodEnter(
|
||||
@Advice.Argument(0) Request request,
|
||||
@Advice.Argument(value = 1, readOnly = false) AsyncHandler<?> asyncHandler,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
span = tracer().startSpan(request);
|
||||
scope = tracer().startScope(span, request.getHeaders());
|
||||
context = tracer().startSpan(parentContext, request, request.getHeaders());
|
||||
scope = context.makeCurrent();
|
||||
|
||||
if (asyncHandler instanceof StreamedAsyncHandler) {
|
||||
asyncHandler =
|
||||
new StreamedAsyncHandlerWrapper(
|
||||
(StreamedAsyncHandler<?>) asyncHandler, span, parentContext);
|
||||
(StreamedAsyncHandler<?>) asyncHandler, context, parentContext);
|
||||
} else if (!(asyncHandler instanceof WebSocketUpgradeHandler)) {
|
||||
// websocket upgrade handlers aren't supported
|
||||
asyncHandler = new AsyncHandlerWrapper(asyncHandler, span, parentContext);
|
||||
asyncHandler = new AsyncHandlerWrapper(asyncHandler, context, parentContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
scope.close();
|
||||
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.playws.v1_0;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.reactivestreams.Publisher;
|
||||
import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler;
|
||||
|
@ -15,8 +14,8 @@ public class StreamedAsyncHandlerWrapper extends AsyncHandlerWrapper
|
|||
private final StreamedAsyncHandler streamedDelegate;
|
||||
|
||||
public StreamedAsyncHandlerWrapper(
|
||||
StreamedAsyncHandler delegate, Span span, Context invocationContext) {
|
||||
super(delegate, span, invocationContext);
|
||||
StreamedAsyncHandler delegate, Context context, Context parentContext) {
|
||||
super(delegate, context, parentContext);
|
||||
streamedDelegate = delegate;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_0;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -22,15 +21,15 @@ import play.shaded.ahc.org.asynchttpclient.netty.request.NettyRequest;
|
|||
|
||||
public class AsyncHandlerWrapper implements AsyncHandler {
|
||||
private final AsyncHandler delegate;
|
||||
private final Span span;
|
||||
private final Context context;
|
||||
private final Context parentContext;
|
||||
|
||||
private final Response.ResponseBuilder builder = new Response.ResponseBuilder();
|
||||
|
||||
public AsyncHandlerWrapper(AsyncHandler delegate, Span span) {
|
||||
public AsyncHandlerWrapper(AsyncHandler delegate, Context context, Context parentContext) {
|
||||
this.delegate = delegate;
|
||||
this.span = span;
|
||||
parentContext = Context.current();
|
||||
this.context = context;
|
||||
this.parentContext = parentContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,7 +54,7 @@ public class AsyncHandlerWrapper implements AsyncHandler {
|
|||
@Override
|
||||
public Object onCompleted() throws Exception {
|
||||
Response response = builder.build();
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
|
||||
try (Scope ignored = parentContext.makeCurrent()) {
|
||||
return delegate.onCompleted();
|
||||
|
@ -64,7 +63,7 @@ public class AsyncHandlerWrapper implements AsyncHandler {
|
|||
|
||||
@Override
|
||||
public void onThrowable(Throwable throwable) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
|
||||
try (Scope ignored = parentContext.makeCurrent()) {
|
||||
delegate.onThrowable(throwable);
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.playws.v2_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
|
@ -37,28 +37,29 @@ public class PlayWsInstrumentationModule extends InstrumentationModule {
|
|||
public static void methodEnter(
|
||||
@Advice.Argument(0) Request request,
|
||||
@Advice.Argument(value = 1, readOnly = false) AsyncHandler<?> asyncHandler,
|
||||
@Advice.Local("otelSpan") Span span) {
|
||||
@Advice.Local("otelContext") Context context) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
span = tracer().startSpan(request);
|
||||
// TODO (trask) expose inject separate from startScope, e.g. for async cases
|
||||
Scope scope = tracer().startScope(span, request.getHeaders());
|
||||
scope.close();
|
||||
context = tracer().startSpan(parentContext, request, request.getHeaders());
|
||||
|
||||
if (asyncHandler instanceof StreamedAsyncHandler) {
|
||||
asyncHandler =
|
||||
new StreamedAsyncHandlerWrapper((StreamedAsyncHandler<?>) asyncHandler, span);
|
||||
new StreamedAsyncHandlerWrapper(
|
||||
(StreamedAsyncHandler<?>) asyncHandler, context, parentContext);
|
||||
} else if (!(asyncHandler instanceof WebSocketUpgradeHandler)) {
|
||||
// websocket upgrade handlers aren't supported
|
||||
asyncHandler = new AsyncHandlerWrapper(asyncHandler, span);
|
||||
asyncHandler = new AsyncHandlerWrapper(asyncHandler, context, parentContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span) {
|
||||
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
@Advice.Thrown Throwable throwable, @Advice.Local("otelContext") Context context) {
|
||||
if (context != null && throwable != null) {
|
||||
tracer().endExceptionally(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.playws.v2_0;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.reactivestreams.Publisher;
|
||||
import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler;
|
||||
|
||||
|
@ -13,8 +13,9 @@ public class StreamedAsyncHandlerWrapper extends AsyncHandlerWrapper
|
|||
implements StreamedAsyncHandler {
|
||||
private final StreamedAsyncHandler streamedDelegate;
|
||||
|
||||
public StreamedAsyncHandlerWrapper(StreamedAsyncHandler delegate, Span span) {
|
||||
super(delegate, span);
|
||||
public StreamedAsyncHandlerWrapper(
|
||||
StreamedAsyncHandler delegate, Context context, Context parentContext) {
|
||||
super(delegate, context, parentContext);
|
||||
streamedDelegate = delegate;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_1;
|
|||
|
||||
import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -23,15 +22,15 @@ import play.shaded.ahc.org.asynchttpclient.netty.request.NettyRequest;
|
|||
|
||||
public class AsyncHandlerWrapper implements AsyncHandler {
|
||||
private final AsyncHandler delegate;
|
||||
private final Span span;
|
||||
private final Context context;
|
||||
private final Context parentContext;
|
||||
|
||||
private final Response.ResponseBuilder builder = new Response.ResponseBuilder();
|
||||
|
||||
public AsyncHandlerWrapper(AsyncHandler delegate, Span span) {
|
||||
public AsyncHandlerWrapper(AsyncHandler delegate, Context context, Context parentContext) {
|
||||
this.delegate = delegate;
|
||||
this.span = span;
|
||||
parentContext = Context.current();
|
||||
this.context = context;
|
||||
this.parentContext = parentContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,7 +55,7 @@ public class AsyncHandlerWrapper implements AsyncHandler {
|
|||
@Override
|
||||
public Object onCompleted() throws Exception {
|
||||
Response response = builder.build();
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
|
||||
try (Scope ignored = parentContext.makeCurrent()) {
|
||||
return delegate.onCompleted();
|
||||
|
@ -65,7 +64,7 @@ public class AsyncHandlerWrapper implements AsyncHandler {
|
|||
|
||||
@Override
|
||||
public void onThrowable(Throwable throwable) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
tracer().endExceptionally(context, throwable);
|
||||
|
||||
try (Scope ignored = parentContext.makeCurrent()) {
|
||||
delegate.onThrowable(throwable);
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.playws.v2_1;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||
import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
|
@ -37,28 +37,29 @@ public class PlayWsInstrumentationModule extends InstrumentationModule {
|
|||
public static void methodEnter(
|
||||
@Advice.Argument(0) Request request,
|
||||
@Advice.Argument(value = 1, readOnly = false) AsyncHandler<?> asyncHandler,
|
||||
@Advice.Local("otelSpan") Span span) {
|
||||
@Advice.Local("otelContext") Context context) {
|
||||
Context parentContext = currentContext();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
span = tracer().startSpan(request);
|
||||
// TODO (trask) expose inject separate from startScope, e.g. for async cases
|
||||
Scope scope = tracer().startScope(span, request.getHeaders());
|
||||
scope.close();
|
||||
context = tracer().startSpan(parentContext, request, request.getHeaders());
|
||||
|
||||
if (asyncHandler instanceof StreamedAsyncHandler) {
|
||||
asyncHandler =
|
||||
new StreamedAsyncHandlerWrapper((StreamedAsyncHandler<?>) asyncHandler, span);
|
||||
new StreamedAsyncHandlerWrapper(
|
||||
(StreamedAsyncHandler<?>) asyncHandler, context, parentContext);
|
||||
} else if (!(asyncHandler instanceof WebSocketUpgradeHandler)) {
|
||||
// websocket upgrade handlers aren't supported
|
||||
asyncHandler = new AsyncHandlerWrapper(asyncHandler, span);
|
||||
asyncHandler = new AsyncHandlerWrapper(asyncHandler, context, parentContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span) {
|
||||
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(span, throwable);
|
||||
@Advice.Thrown Throwable throwable, @Advice.Local("otelContext") Context context) {
|
||||
if (context != null && throwable != null) {
|
||||
tracer().endExceptionally(context, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.playws.v2_1;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.reactivestreams.Publisher;
|
||||
import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler;
|
||||
|
||||
|
@ -13,8 +13,9 @@ public class StreamedAsyncHandlerWrapper extends AsyncHandlerWrapper
|
|||
implements StreamedAsyncHandler {
|
||||
private final StreamedAsyncHandler streamedDelegate;
|
||||
|
||||
public StreamedAsyncHandlerWrapper(StreamedAsyncHandler delegate, Span span) {
|
||||
super(delegate, span);
|
||||
public StreamedAsyncHandlerWrapper(
|
||||
StreamedAsyncHandler delegate, Context context, Context parentContext) {
|
||||
super(delegate, context, parentContext);
|
||||
streamedDelegate = delegate;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||
|
@ -65,7 +65,7 @@ public class HttpServletResponseInstrumentationModule extends InstrumentationMod
|
|||
@Advice.Origin Method method,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
callDepth = CallDepthThreadLocalMap.getCallDepth(HttpServletResponse.class);
|
||||
// Don't want to generate a new top-level span
|
||||
if (callDepth.getAndIncrement() == 0
|
||||
|
@ -80,7 +80,7 @@ public class HttpServletResponseInstrumentationModule extends InstrumentationMod
|
|||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelSpan") Span span,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Local("otelCallDepth") Depth callDepth) {
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
if (callDepth.decrementAndGet() == 0 && span != null) {
|
||||
CallDepthThreadLocalMap.reset(HttpServletResponse.class);
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ package io.opentelemetry.instrumentation.spring.httpclients;
|
|||
|
||||
import static io.opentelemetry.instrumentation.spring.httpclients.RestTemplateTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
import org.springframework.http.HttpRequest;
|
||||
|
@ -28,11 +28,15 @@ public final class RestTemplateInterceptor implements ClientHttpRequestIntercept
|
|||
@Override
|
||||
public ClientHttpResponse intercept(
|
||||
HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
||||
Context parentContext = Context.current();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
|
||||
Span span = tracer().startSpan(request);
|
||||
try (Scope scope = tracer().startScope(span, request.getHeaders())) {
|
||||
Context context = tracer().startSpan(parentContext, request, request.getHeaders());
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
ClientHttpResponse response = execution.execute(request, body);
|
||||
tracer().end(span, response);
|
||||
tracer().end(context, response);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import static io.opentelemetry.instrumentation.spring.webflux.client.HttpHeaders
|
|||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
@ -30,7 +31,8 @@ public class SpringWebfluxHttpClientTracer
|
|||
|
||||
private static final MethodHandle RAW_STATUS_CODE = findRawStatusCode();
|
||||
|
||||
public void onCancel(Span span) {
|
||||
public void onCancel(Context context) {
|
||||
Span span = Span.fromContext(context);
|
||||
span.setAttribute("event", "cancelled");
|
||||
span.setAttribute("message", "The subscription was cancelled");
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ package io.opentelemetry.instrumentation.spring.webflux.client;
|
|||
|
||||
import static io.opentelemetry.instrumentation.spring.webflux.client.SpringWebfluxHttpClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import org.reactivestreams.Subscription;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
|
@ -23,15 +22,12 @@ public final class TraceWebClientSubscriber implements CoreSubscriber<ClientResp
|
|||
|
||||
final reactor.util.context.Context context;
|
||||
|
||||
private final Span span;
|
||||
private final io.opentelemetry.context.Context tracingContext;
|
||||
|
||||
public TraceWebClientSubscriber(
|
||||
CoreSubscriber<? super ClientResponse> actual,
|
||||
Span span,
|
||||
io.opentelemetry.context.Context tracingContext) {
|
||||
this.actual = actual;
|
||||
this.span = span;
|
||||
this.tracingContext = tracingContext;
|
||||
this.context = actual.currentContext();
|
||||
}
|
||||
|
@ -46,7 +42,7 @@ public final class TraceWebClientSubscriber implements CoreSubscriber<ClientResp
|
|||
try (Scope ignored = tracingContext.makeCurrent()) {
|
||||
this.actual.onNext(response);
|
||||
} finally {
|
||||
tracer().end(span, response);
|
||||
tracer().end(tracingContext, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +51,7 @@ public final class TraceWebClientSubscriber implements CoreSubscriber<ClientResp
|
|||
try (Scope ignored = tracingContext.makeCurrent()) {
|
||||
this.actual.onError(t);
|
||||
} finally {
|
||||
tracer().endExceptionally(span, t);
|
||||
tracer().endExceptionally(tracingContext, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package io.opentelemetry.instrumentation.spring.webflux.client;
|
|||
|
||||
import static io.opentelemetry.instrumentation.spring.webflux.client.SpringWebfluxHttpClientTracer.tracer;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.util.List;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
|
@ -49,19 +49,22 @@ public class WebClientTracingFilter implements ExchangeFilterFunction {
|
|||
|
||||
@Override
|
||||
public void subscribe(CoreSubscriber<? super ClientResponse> subscriber) {
|
||||
Span span = tracer().startSpan(request);
|
||||
Context parentContext = Context.current();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClientRequest.Builder builder = ClientRequest.from(request);
|
||||
try (Scope ignored = tracer().startScope(span, builder)) {
|
||||
Context context = tracer().startSpan(parentContext, request, builder);
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
this.next
|
||||
.exchange(builder.build())
|
||||
.doOnCancel(
|
||||
() -> {
|
||||
tracer().onCancel(span);
|
||||
tracer().end(span);
|
||||
tracer().onCancel(context);
|
||||
tracer().end(context);
|
||||
})
|
||||
.subscribe(
|
||||
new TraceWebClientSubscriber(
|
||||
subscriber, span, io.opentelemetry.context.Context.current()));
|
||||
.subscribe(new TraceWebClientSubscriber(subscriber, context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.api;
|
||||
|
||||
public final class CallDepth {
|
||||
private int depth;
|
||||
|
||||
CallDepth() {
|
||||
this.depth = 0;
|
||||
}
|
||||
|
||||
public int getAndIncrement() {
|
||||
return this.depth++;
|
||||
}
|
||||
|
||||
public int decrementAndGet() {
|
||||
return --this.depth;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
depth = 0;
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ public class CallDepthThreadLocalMap {
|
|||
}
|
||||
};
|
||||
|
||||
public static Depth getCallDepth(Class<?> k) {
|
||||
public static CallDepth getCallDepth(Class<?> k) {
|
||||
return TLS.get(k).get();
|
||||
}
|
||||
|
||||
|
@ -43,29 +43,13 @@ public class CallDepthThreadLocalMap {
|
|||
}
|
||||
|
||||
public static void reset(Class<?> k) {
|
||||
TLS.get(k).get().depth = 0;
|
||||
TLS.get(k).get().reset();
|
||||
}
|
||||
|
||||
public static final class Depth {
|
||||
private int depth;
|
||||
|
||||
private Depth() {
|
||||
this.depth = 0;
|
||||
}
|
||||
|
||||
public int getAndIncrement() {
|
||||
return this.depth++;
|
||||
}
|
||||
|
||||
public int decrementAndGet() {
|
||||
return --this.depth;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ThreadLocalDepth extends ThreadLocal<Depth> {
|
||||
private static final class ThreadLocalDepth extends ThreadLocal<CallDepth> {
|
||||
@Override
|
||||
protected Depth initialValue() {
|
||||
return new Depth();
|
||||
protected CallDepth initialValue() {
|
||||
return new CallDepth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ import io.opentelemetry.context.Scope;
|
|||
* <li>The new pattern is more efficient since it doesn't require instantiating the {@code
|
||||
* SpanWithScope} holder object
|
||||
* <li>The new pattern extends nicely in the common case where we also need to pass {@link
|
||||
* CallDepthThreadLocalMap.Depth} between the methods
|
||||
* CallDepth} between the methods
|
||||
* </ul>
|
||||
*
|
||||
* @deprecated see above
|
||||
|
|
Loading…
Reference in New Issue