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