diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java index 3a58723b51..204f60a656 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java @@ -12,7 +12,6 @@ import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.attributes.SemanticAttributes; import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils; @@ -60,60 +59,63 @@ public abstract class HttpClientTracer extends BaseT super(tracer); } - public Span startSpan(REQUEST request) { - return startSpan(request, -1); + public boolean shouldStartSpan(Context parentContext) { + return parentContext.get(CONTEXT_CLIENT_SPAN_KEY) == null; } - public Span startSpan(REQUEST request, long startTimeNanos) { - return internalStartSpan(request, spanNameForRequest(request), startTimeNanos); + public Context startSpan(Context parentContext, REQUEST request, CARRIER carrier) { + return startSpan(parentContext, request, carrier, -1); } - public Scope startScope(Span span, CARRIER carrier) { - Context context = Context.current().with(span); - + public Context startSpan( + Context parentContext, REQUEST request, CARRIER carrier, long startTimeNanos) { + Span span = + internalStartSpan(parentContext, request, spanNameForRequest(request), startTimeNanos); Setter setter = getSetter(); if (setter == null) { throw new IllegalStateException( "getSetter() not defined but calling startScope(), either getSetter must be implemented or the scope should be setup manually"); } + Context context = parentContext.with(span).with(CONTEXT_CLIENT_SPAN_KEY, span); OpenTelemetry.getGlobalPropagators().getTextMapPropagator().inject(context, carrier, setter); - context = context.with(CONTEXT_CLIENT_SPAN_KEY, span); - return context.makeCurrent(); + return context; } - public void end(Span span, RESPONSE response) { - end(span, response, -1); + public void end(Context context, RESPONSE response) { + end(context, response, -1); } - public void end(Span span, RESPONSE response, long endTimeNanos) { + public void end(Context context, RESPONSE response, long endTimeNanos) { + Span span = Span.fromContext(context); onResponse(span, response); super.end(span, endTimeNanos); } - public void endExceptionally(Span span, RESPONSE response, Throwable throwable) { - endExceptionally(span, response, throwable, -1); + public void end(Context context) { + Span span = Span.fromContext(context); + super.end(span); + } + + public void endExceptionally(Context context, RESPONSE response, Throwable throwable) { + endExceptionally(context, response, throwable, -1); } public void endExceptionally( - Span span, RESPONSE response, Throwable throwable, long endTimeNanos) { + Context context, RESPONSE response, Throwable throwable, long endTimeNanos) { + Span span = Span.fromContext(context); onResponse(span, response); super.endExceptionally(span, throwable, endTimeNanos); } - /** - * Returns a new client {@link Span} if there is no client {@link Span} in the current {@link - * Context}, or an invalid {@link Span} otherwise. - */ - private Span internalStartSpan(REQUEST request, String name, long startTimeNanos) { - Context context = Context.current(); - Span clientSpan = context.get(CONTEXT_CLIENT_SPAN_KEY); + public void endExceptionally(Context context, Throwable throwable) { + Span span = Span.fromContext(context); + super.endExceptionally(span, throwable, -1); + } - if (clientSpan != null) { - // We don't want to create two client spans for a given client call, suppress inner spans. - return Span.getInvalid(); - } - - SpanBuilder spanBuilder = tracer.spanBuilder(name).setSpanKind(Kind.CLIENT).setParent(context); + private Span internalStartSpan( + Context parentContext, REQUEST request, String name, long startTimeNanos) { + SpanBuilder spanBuilder = + tracer.spanBuilder(name).setSpanKind(Kind.CLIENT).setParent(parentContext); if (startTimeNanos > 0) { spanBuilder.setStartTimestamp(startTimeNanos, TimeUnit.NANOSECONDS); } diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java index 7c8f115ab0..888de6a4fc 100644 --- a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.akkahttp; import static io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -14,10 +15,9 @@ import akka.http.scaladsl.HttpExt; import akka.http.scaladsl.model.HttpRequest; import akka.http.scaladsl.model.HttpResponse; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapPropagator; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.util.Collections; @@ -70,23 +70,24 @@ public class AkkaHttpClientInstrumentationModule extends InstrumentationModule { @Advice.OnMethodEnter(suppress = Throwable.class) public static void methodEnter( @Advice.Argument(value = 0, readOnly = false) HttpRequest request, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { /* Versions 10.0 and 10.1 have slightly different structure that is hard to distinguish so here we cast 'wider net' and avoid instrumenting twice. In the future we may want to separate these, but since lots of code is reused we would need to come up with way of continuing to reusing it. */ - callDepth = tracer().getCallDepth(); - if (callDepth.getAndIncrement() == 0) { - span = tracer().startSpan(request); - // Request is immutable, so we have to assign new value once we update headers - AkkaHttpHeaders headers = new AkkaHttpHeaders(request); - scope = tracer().startScope(span, headers); - request = headers.getRequest(); + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } + + // Request is immutable, so we have to assign new value once we update headers + AkkaHttpHeaders headers = new AkkaHttpHeaders(request); + context = tracer().startSpan(parentContext, request, headers); + scope = context.makeCurrent(); + request = headers.getRequest(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @@ -95,33 +96,34 @@ public class AkkaHttpClientInstrumentationModule extends InstrumentationModule { @Advice.This HttpExt thiz, @Advice.Return Future responseFuture, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { - if (callDepth.decrementAndGet() == 0 && scope != null) { - scope.close(); - if (throwable == null) { - responseFuture.onComplete(new OnCompleteHandler(span), thiz.system().dispatcher()); - } else { - tracer().endExceptionally(span, throwable); - } + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + if (throwable == null) { + responseFuture.onComplete(new OnCompleteHandler(context), thiz.system().dispatcher()); + } else { + tracer().endExceptionally(context, throwable); } } } public static class OnCompleteHandler extends AbstractFunction1, Void> { - private final Span span; + private final Context context; - public OnCompleteHandler(Span span) { - this.span = span; + public OnCompleteHandler(Context context) { + this.context = context; } @Override public Void apply(Try result) { if (result.isSuccess()) { - tracer().end(span, result.get()); + tracer().end(context, result.get()); } else { - tracer().endExceptionally(span, result.failed().get()); + tracer().endExceptionally(context, result.failed().get()); } return null; } diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientTracer.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientTracer.java index 90366dd866..919d228ae7 100644 --- a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientTracer.java +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientTracer.java @@ -8,14 +8,11 @@ package io.opentelemetry.javaagent.instrumentation.akkahttp; import static io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientInstrumentationModule.InjectAdapter.SETTER; import akka.http.javadsl.model.HttpHeader; -import akka.http.scaladsl.HttpExt; import akka.http.scaladsl.model.HttpRequest; import akka.http.scaladsl.model.HttpResponse; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; import io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientInstrumentationModule.AkkaHttpHeaders; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import java.net.URI; import java.net.URISyntaxException; @@ -27,10 +24,6 @@ public class AkkaHttpClientTracer return TRACER; } - public Depth getCallDepth() { - return CallDepthThreadLocalMap.getCallDepth(HttpExt.class); - } - @Override protected String method(HttpRequest httpRequest) { return httpRequest.method().value(); diff --git a/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java b/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java index 51adb3df62..c12089ed0c 100644 --- a/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java +++ b/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java @@ -5,8 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient; -import static io.opentelemetry.instrumentation.api.tracer.HttpClientTracer.DEFAULT_SPAN_NAME; import static io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed; import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; @@ -15,11 +15,10 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Span.Kind; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.io.IOException; import java.util.Map; @@ -66,36 +65,41 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation public static class ClientAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static Span methodEnter( + public static void methodEnter( @Advice.Argument(value = 0, readOnly = false) HttpAsyncRequestProducer requestProducer, - @Advice.Argument(2) HttpContext context, - @Advice.Argument(value = 3, readOnly = false) FutureCallback futureCallback) { + @Advice.Argument(2) HttpContext httpContext, + @Advice.Argument(value = 3, readOnly = false) FutureCallback futureCallback, + @Advice.Local("otelContext") Context context) { - Context parentContext = Java8BytecodeBridge.currentContext(); - Span clientSpan = tracer().startSpan(DEFAULT_SPAN_NAME, Kind.CLIENT); + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } - requestProducer = new DelegatingRequestProducer(clientSpan, requestProducer); + context = tracer().startSpan(parentContext); + + requestProducer = new DelegatingRequestProducer(context, requestProducer); futureCallback = - new TraceContinuedFutureCallback<>(parentContext, clientSpan, context, futureCallback); - - return clientSpan; + new TraceContinuedFutureCallback<>(parentContext, context, httpContext, futureCallback); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( - @Advice.Enter Span span, @Advice.Return Object result, @Advice.Thrown Throwable throwable) { - if (throwable != null) { - tracer().endExceptionally(span, throwable); + @Advice.Return Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context) { + if (context != null && throwable != null) { + tracer().endExceptionally(context, throwable); } } } public static class DelegatingRequestProducer implements HttpAsyncRequestProducer { - Span span; + Context context; HttpAsyncRequestProducer delegate; - public DelegatingRequestProducer(Span span, HttpAsyncRequestProducer delegate) { - this.span = span; + public DelegatingRequestProducer(Context context, HttpAsyncRequestProducer delegate) { + this.context = context; this.delegate = delegate; } @@ -107,13 +111,12 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation @Override public HttpRequest generateRequest() throws IOException, HttpException { HttpRequest request = delegate.generateRequest(); + OpenTelemetry.getGlobalPropagators() + .getTextMapPropagator() + .inject(context, request, tracer().getSetter()); + Span span = Span.fromContext(context); span.updateName(tracer().spanNameForRequest(request)); tracer().onRequest(span, request); - - // TODO (trask) expose inject separate from startScope, e.g. for async cases - Scope scope = tracer().startScope(span, request); - scope.close(); - return request; } @@ -150,22 +153,25 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation public static class TraceContinuedFutureCallback implements FutureCallback { private final Context parentContext; - private final Span clientSpan; - private final HttpContext context; + private final Context context; + private final HttpContext httpContext; private final FutureCallback delegate; public TraceContinuedFutureCallback( - Context parentContext, Span clientSpan, HttpContext context, FutureCallback delegate) { + Context parentContext, + Context context, + HttpContext httpContext, + FutureCallback delegate) { this.parentContext = parentContext; - this.clientSpan = clientSpan; this.context = context; + this.httpContext = httpContext; // Note: this can be null in real life, so we have to handle this carefully this.delegate = delegate; } @Override public void completed(T result) { - tracer().end(clientSpan, getResponse(context)); + tracer().end(context, getResponse(httpContext)); if (parentContext == null) { completeDelegate(result); @@ -179,7 +185,7 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation @Override public void failed(Exception ex) { // end span before calling delegate - tracer().endExceptionally(clientSpan, getResponse(context), ex); + tracer().endExceptionally(context, getResponse(httpContext), ex); if (parentContext == null) { failDelegate(ex); @@ -193,7 +199,7 @@ public class ApacheHttpAsyncClientInstrumentation implements TypeInstrumentation @Override public void cancelled() { // end span before calling delegate - tracer().end(clientSpan, getResponse(context)); + tracer().end(context, getResponse(httpContext)); if (parentContext == null) { cancelDelegate(); diff --git a/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientTracer.java b/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientTracer.java index 7248aa8102..131d1a8092 100644 --- a/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientTracer.java +++ b/instrumentation/apache-httpasyncclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientTracer.java @@ -5,9 +5,11 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient; +import static io.opentelemetry.api.trace.Span.Kind.CLIENT; import static io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient.HttpHeadersInjectAdapter.SETTER; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; import java.net.URI; @@ -30,6 +32,16 @@ public class ApacheHttpAsyncClientTracer return TRACER; } + public Context startSpan(Context parentContext) { + Span span = + tracer + .spanBuilder(DEFAULT_SPAN_NAME) + .setSpanKind(CLIENT) + .setParent(parentContext) + .startSpan(); + return parentContext.with(span).with(CONTEXT_CLIENT_SPAN_KEY, span); + } + @Override protected String method(HttpRequest request) { if (request instanceof HttpUriRequest) { diff --git a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientInstrumentationModule.java b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientInstrumentationModule.java index 940b2fd800..07e6317564 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientInstrumentationModule.java +++ b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientInstrumentationModule.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0; import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0.CommonsHttpClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed; import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass; import static java.util.Collections.singletonList; @@ -16,9 +17,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.util.List; @@ -67,34 +67,32 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule @Advice.OnMethodEnter(suppress = Throwable.class) public static void methodEnter( @Advice.Argument(1) HttpMethod httpMethod, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { - - callDepth = tracer().getCallDepth(); - if (callDepth.getAndIncrement() == 0) { - span = tracer().startSpan(httpMethod); - if (span.getSpanContext().isValid()) { - scope = tracer().startScope(span, httpMethod); - } + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } + + context = tracer().startSpan(parentContext, httpMethod, httpMethod); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Argument(1) HttpMethod httpMethod, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } - if (callDepth.decrementAndGet() == 0 && scope != null) { - scope.close(); - if (throwable == null) { - tracer().end(span, httpMethod); - } else { - tracer().endExceptionally(span, httpMethod, throwable); - } + scope.close(); + if (throwable == null) { + tracer().end(context, httpMethod); + } else { + tracer().endExceptionally(context, httpMethod, throwable); } } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/CommonsHttpClientTracer.java b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/CommonsHttpClientTracer.java index ae91a49489..3dab27e0b7 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/CommonsHttpClientTracer.java +++ b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/CommonsHttpClientTracer.java @@ -7,12 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import java.net.URI; import java.net.URISyntaxException; import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.StatusLine; import org.apache.commons.httpclient.URIException; @@ -29,10 +26,6 @@ public class CommonsHttpClientTracer extends HttpClientTracer 0) { - return null; + public static void methodEnter( + @Advice.Argument(0) HttpUriRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } - return ApacheHttpClientHelper.doMethodEnter(request); + context = tracer().startSpan(parentContext, request, request); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( - @Advice.Enter SpanWithScope spanWithScope, @Advice.Return Object result, - @Advice.Thrown Throwable throwable) { - ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable); + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + ApacheHttpClientHelper.doMethodExit(context, result, throwable); } } public static class UriRequestWithHandlerAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static SpanWithScope methodEnter( + public static void methodEnter( @Advice.Argument(0) HttpUriRequest request, @Advice.Argument( value = 1, optional = true, typing = Assigner.Typing.DYNAMIC, readOnly = false) - Object handler) { - int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class); - if (callDepth > 0) { - return null; + Object handler, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } - SpanWithScope spanWithScope = ApacheHttpClientHelper.doMethodEnter(request); + context = tracer().startSpan(parentContext, request, request); + scope = context.makeCurrent(); // Wrap the handler so we capture the status code if (handler instanceof ResponseHandler) { - handler = - new WrappingStatusSettingResponseHandler( - spanWithScope.getSpan(), (ResponseHandler) handler); + handler = new WrappingStatusSettingResponseHandler(context, (ResponseHandler) handler); } - return spanWithScope; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( - @Advice.Enter SpanWithScope spanWithScope, @Advice.Return Object result, - @Advice.Thrown Throwable throwable) { - ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable); + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + ApacheHttpClientHelper.doMethodExit(context, result, throwable); } } public static class RequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static SpanWithScope methodEnter( - @Advice.Argument(0) HttpHost host, @Advice.Argument(1) HttpRequest request) { - int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class); - if (callDepth > 0) { - return null; + public static void methodEnter( + @Advice.Argument(0) HttpHost host, + @Advice.Argument(1) HttpRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } + HttpUriRequest httpUriRequest; if (request instanceof HttpUriRequest) { - return ApacheHttpClientHelper.doMethodEnter((HttpUriRequest) request); + httpUriRequest = (HttpUriRequest) request; } else { - return ApacheHttpClientHelper.doMethodEnter( - new HostAndRequestAsHttpUriRequest(host, request)); + httpUriRequest = new HostAndRequestAsHttpUriRequest(host, request); } + context = tracer().startSpan(parentContext, httpUriRequest, httpUriRequest); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( - @Advice.Enter SpanWithScope spanWithScope, @Advice.Return Object result, - @Advice.Thrown Throwable throwable) { - ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable); + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + ApacheHttpClientHelper.doMethodExit(context, result, throwable); } } public static class RequestWithHandlerAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static SpanWithScope methodEnter( + public static void methodEnter( @Advice.Argument(0) HttpHost host, @Advice.Argument(1) HttpRequest request, @Advice.Argument( @@ -238,36 +266,41 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule optional = true, typing = Assigner.Typing.DYNAMIC, readOnly = false) - Object handler) { - int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class); - if (callDepth > 0) { - return null; + Object handler, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } - SpanWithScope spanWithScope; - + HttpUriRequest httpUriRequest; if (request instanceof HttpUriRequest) { - spanWithScope = ApacheHttpClientHelper.doMethodEnter((HttpUriRequest) request); + httpUriRequest = (HttpUriRequest) request; } else { - spanWithScope = - ApacheHttpClientHelper.doMethodEnter(new HostAndRequestAsHttpUriRequest(host, request)); + httpUriRequest = new HostAndRequestAsHttpUriRequest(host, request); } + context = tracer().startSpan(parentContext, httpUriRequest, httpUriRequest); + scope = context.makeCurrent(); // Wrap the handler so we capture the status code if (handler instanceof ResponseHandler) { - handler = - new WrappingStatusSettingResponseHandler( - spanWithScope.getSpan(), (ResponseHandler) handler); + handler = new WrappingStatusSettingResponseHandler(context, (ResponseHandler) handler); } - return spanWithScope; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( - @Advice.Enter SpanWithScope spanWithScope, @Advice.Return Object result, - @Advice.Thrown Throwable throwable) { - ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable); + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + ApacheHttpClientHelper.doMethodExit(context, result, throwable); } } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientTracer.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientTracer.java index f46fb4c725..0253eed1cd 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientTracer.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientTracer.java @@ -17,7 +17,7 @@ import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.checkerframework.checker.nullness.qual.Nullable; -class ApacheHttpClientTracer +public class ApacheHttpClientTracer extends HttpClientTracer { private static final ApacheHttpClientTracer TRACER = new ApacheHttpClientTracer(); diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ContextScopePair.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ContextScopePair.java new file mode 100644 index 0000000000..63e4092b45 --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ContextScopePair.java @@ -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(); + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java index 0904e0ddea..15581e4f64 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java @@ -8,24 +8,24 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientTracer.tracer; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import java.io.IOException; import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; public class WrappingStatusSettingResponseHandler implements ResponseHandler { - final Span span; + final Context context; final ResponseHandler handler; - public WrappingStatusSettingResponseHandler(Span span, ResponseHandler handler) { - this.span = span; + public WrappingStatusSettingResponseHandler(Context context, ResponseHandler handler) { + this.context = context; this.handler = handler; } @Override - public Object handleResponse(HttpResponse response) throws ClientProtocolException, IOException { - if (null != span) { - tracer().onResponse(span, response); + public Object handleResponse(HttpResponse response) throws IOException { + if (context != null) { + tracer().onResponse(Span.fromContext(context), response); } return handler.handleResponse(response); } diff --git a/instrumentation/armeria-1.0/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_0/client/OpenTelemetryClient.java b/instrumentation/armeria-1.0/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_0/client/OpenTelemetryClient.java index 561c537388..9fb0e63749 100644 --- a/instrumentation/armeria-1.0/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_0/client/OpenTelemetryClient.java +++ b/instrumentation/armeria-1.0/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_0/client/OpenTelemetryClient.java @@ -13,6 +13,7 @@ import com.linecorp.armeria.common.HttpResponse; import com.linecorp.armeria.common.logging.RequestLogProperty; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils; import java.util.concurrent.TimeUnit; @@ -52,8 +53,9 @@ public class OpenTelemetryClient extends SimpleDecoratingHttpClient { long requestStartTimeMicros = ctx.log().ensureAvailable(RequestLogProperty.REQUEST_START_TIME).requestStartTimeMicros(); long requestStartTimeNanos = TimeUnit.MICROSECONDS.toNanos(requestStartTimeMicros); - Span span = clientTracer.startSpan(ctx, requestStartTimeNanos); + Context context = clientTracer.startSpan(Context.current(), ctx, ctx, requestStartTimeNanos); + Span span = Span.fromContext(context); if (span.isRecording()) { ctx.log() .whenComplete() @@ -64,14 +66,14 @@ public class OpenTelemetryClient extends SimpleDecoratingHttpClient { long requestEndTimeNanos = requestStartTimeNanos + log.responseDurationNanos(); if (log.responseCause() != null) { clientTracer.endExceptionally( - span, log, log.responseCause(), requestEndTimeNanos); + context, log, log.responseCause(), requestEndTimeNanos); } else { - clientTracer.end(span, log, requestEndTimeNanos); + clientTracer.end(context, log, requestEndTimeNanos); } }); } - try (Scope ignored = clientTracer.startScope(span, ctx)) { + try (Scope ignored = context.makeCurrent()) { return unwrap().execute(ctx, req); } } diff --git a/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/RequestAdvice.java b/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/RequestAdvice.java index 6d1ae8c5c3..dcf7b7405b 100644 --- a/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/RequestAdvice.java +++ b/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/RequestAdvice.java @@ -5,32 +5,40 @@ package io.opentelemetry.javaagent.instrumentation.asynchttpclient; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.asynchttpclient.AsyncHttpClientTracer.tracer; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.Request; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.api.Pair; import net.bytebuddy.asm.Advice; public class RequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static Scope onEnter( - @Advice.Argument(0) Request request, @Advice.Argument(1) AsyncHandler handler) { - Context parentContext = Java8BytecodeBridge.currentContext(); + public static void onEnter( + @Advice.Argument(0) Request request, + @Advice.Argument(1) AsyncHandler handler, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } - Span span = AsyncHttpClientTracer.tracer().startSpan(request); + Context context = tracer().startSpan(parentContext, request, request); InstrumentationContext.get(AsyncHandler.class, Pair.class) - .put(handler, Pair.of(parentContext, span)); - return AsyncHttpClientTracer.tracer().startScope(span, request); + .put(handler, Pair.of(parentContext, context)); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit(@Advice.Enter Scope scope) { - // span closed in ClientResponseAdvice - scope.close(); + public static void onExit(@Advice.Local("otelScope") Scope scope) { + if (scope != null) { + scope.close(); + } + // span ended in ClientResponseAdvice } } diff --git a/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/ResponseAdvice.java b/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/ResponseAdvice.java index 513ffc18de..cf166e1d77 100644 --- a/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/ResponseAdvice.java +++ b/instrumentation/async-http-client-1.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/ResponseAdvice.java @@ -8,7 +8,6 @@ package io.opentelemetry.javaagent.instrumentation.asynchttpclient; import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncHandler; import com.ning.http.client.Response; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.instrumentation.api.ContextStore; @@ -26,14 +25,13 @@ public class ResponseAdvice { // After response was handled by user provided handler. ContextStore contextStore = InstrumentationContext.get(AsyncHandler.class, Pair.class); - Pair spanWithParent = contextStore.get(handler); - if (null != spanWithParent) { - contextStore.put(handler, null); + Pair parentAndChildContext = contextStore.get(handler); + if (parentAndChildContext == null) { + return null; } - if (spanWithParent.hasRight()) { - AsyncHttpClientTracer.tracer().end(spanWithParent.getRight(), response); - } - return spanWithParent.hasLeft() ? spanWithParent.getLeft().makeCurrent() : null; + contextStore.put(handler, null); + AsyncHttpClientTracer.tracer().end(parentAndChildContext.getRight(), response); + return parentAndChildContext.getLeft().makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsHttpClientInstrumentation.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsHttpClientInstrumentation.java index 47079d5329..fc9e499a84 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsHttpClientInstrumentation.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsHttpClientInstrumentation.java @@ -6,7 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11; import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer; -import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.SPAN_SCOPE_PAIR_CONTEXT_KEY; +import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; import static net.bytebuddy.matcher.ElementMatchers.isMethod; @@ -16,7 +16,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import com.amazonaws.AmazonClientException; import com.amazonaws.Request; import com.amazonaws.handlers.RequestHandler2; -import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.util.Map; import net.bytebuddy.asm.Advice; @@ -49,10 +48,10 @@ public class AwsHttpClientInstrumentation implements TypeInstrumentation { @Advice.Argument(value = 0, optional = true) Request request, @Advice.Thrown Throwable throwable) { if (throwable != null) { - SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY); + ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY); if (scope != null) { - request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null); - tracer().endExceptionally(scope.getSpan(), throwable); + request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null); + tracer().endExceptionally(scope.getContext(), throwable); scope.closeScope(); } } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkClientTracer.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkClientTracer.java index 6b373841ef..63b123334b 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkClientTracer.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkClientTracer.java @@ -10,6 +10,7 @@ import com.amazonaws.AmazonWebServiceResponse; import com.amazonaws.Request; import com.amazonaws.Response; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; import java.net.URI; @@ -39,8 +40,9 @@ public class AwsSdkClientTracer extends HttpClientTracer, Request, return qualifiedOperation(awsServiceName, awsOperation); } - public Span startSpan(Request request, RequestMeta requestMeta) { - Span span = super.startSpan(request); + public Context startSpan(Context parentContext, Request request, RequestMeta requestMeta) { + Context context = super.startSpan(parentContext, request, request); + Span span = Span.fromContext(context); String awsServiceName = request.getServiceName(); AmazonWebServiceRequest originalRequest = request.getOriginalRequest(); @@ -58,7 +60,7 @@ public class AwsSdkClientTracer extends HttpClientTracer, Request, span.setAttribute("aws.stream.name", requestMeta.getStreamName()); span.setAttribute("aws.table.name", requestMeta.getTableName()); } - return span; + return context; } @Override diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/ContextScopePair.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/ContextScopePair.java new file mode 100644 index 0000000000..c10cccf1c3 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/ContextScopePair.java @@ -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(); + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestExecutorInstrumentation.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestExecutorInstrumentation.java index 6934483b10..3a0efb278d 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestExecutorInstrumentation.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestExecutorInstrumentation.java @@ -6,7 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11; import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer; -import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.SPAN_SCOPE_PAIR_CONTEXT_KEY; +import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; import static net.bytebuddy.matcher.ElementMatchers.isMethod; @@ -14,7 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import com.amazonaws.Request; -import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.util.Map; import net.bytebuddy.asm.Advice; @@ -45,10 +44,10 @@ public class RequestExecutorInstrumentation implements TypeInstrumentation { public static void methodExit( @Advice.FieldValue("request") Request request, @Advice.Thrown Throwable throwable) { if (throwable != null) { - SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY); + ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY); if (scope != null) { - request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null); - tracer().endExceptionally(scope.getSpan(), throwable); + request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null); + tracer().endExceptionally(scope.getContext(), throwable); scope.closeScope(); } } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestMeta.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestMeta.java index 24edd079a8..a42b4cbcba 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestMeta.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestMeta.java @@ -6,14 +6,13 @@ package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11; import com.amazonaws.handlers.HandlerContextKey; -import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope; import java.util.Objects; public class RequestMeta { // Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context // safely. - public static final HandlerContextKey SPAN_SCOPE_PAIR_CONTEXT_KEY = - new HandlerContextKey<>("io.opentelemetry.auto.SpanWithScope"); + public static final HandlerContextKey CONTEXT_SCOPE_PAIR_CONTEXT_KEY = + new HandlerContextKey<>(RequestMeta.class.getName() + ".ContextSpanPair"); private String bucketName; private String queueUrl; diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/TracingRequestHandler.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/TracingRequestHandler.java index cb68f8d413..ce16ca9dfa 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/TracingRequestHandler.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/TracingRequestHandler.java @@ -6,16 +6,15 @@ package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11; import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer; -import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.SPAN_SCOPE_PAIR_CONTEXT_KEY; +import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY; import com.amazonaws.AmazonWebServiceRequest; import com.amazonaws.Request; import com.amazonaws.Response; import com.amazonaws.handlers.RequestHandler2; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.instrumentation.api.ContextStore; -import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope; /** Tracing Request Handler. */ public class TracingRequestHandler extends RequestHandler2 { @@ -30,28 +29,32 @@ public class TracingRequestHandler extends RequestHandler2 { public void beforeRequest(Request request) { AmazonWebServiceRequest originalRequest = request.getOriginalRequest(); RequestMeta requestMeta = contextStore.get(originalRequest); - Span span = tracer().startSpan(request, requestMeta); - Scope scope = tracer().startScope(span, request); - request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, new SpanWithScope(span, scope)); + Context parentContext = Context.current(); + if (tracer().shouldStartSpan(parentContext)) { + Context context = tracer().startSpan(parentContext, request, requestMeta); + Scope scope = context.makeCurrent(); + request.addHandlerContext( + CONTEXT_SCOPE_PAIR_CONTEXT_KEY, new ContextScopePair(context, scope)); + } } @Override public void afterResponse(Request request, Response response) { - SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY); + ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY); if (scope != null) { - request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null); + request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null); scope.closeScope(); - tracer().end(scope.getSpan(), response); + tracer().end(scope.getContext(), response); } } @Override public void afterError(Request request, Response response, Exception e) { - SpanWithScope scope = request.getHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY); + ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY); if (scope != null) { - request.addHandlerContext(SPAN_SCOPE_PAIR_CONTEXT_KEY, null); + request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null); scope.closeScope(); - tracer().endExceptionally(scope.getSpan(), response, e); + tracer().endExceptionally(scope.getContext(), response, e); } } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java index 550262fc3f..4148850017 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java @@ -58,15 +58,6 @@ public class AwsSdk { return new TracingExecutionInterceptor(kind); } - /** - * Returns the {@link Span} stored in the {@link ExecutionAttributes}, or {@code null} if there is - * no span set. - */ - public static Span getSpanFromAttributes(ExecutionAttributes attributes) { - Context context = getContextFromAttributes(attributes); - return context == null ? Span.getInvalid() : Span.fromContext(context); - } - /** * Returns the {@link Span} stored in the {@link ExecutionAttributes}, or {@code null} if there is * no span set. diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java index 265512975e..e4188be373 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java @@ -5,7 +5,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getSpanFromAttributes; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getContextFromAttributes; import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer.tracer; import static io.opentelemetry.instrumentation.awssdk.v2_2.RequestType.ofSdkRequest; @@ -108,8 +108,9 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor { @Override public void afterMarshalling( Context.AfterMarshalling context, ExecutionAttributes executionAttributes) { - Span span = getSpanFromAttributes(executionAttributes); - if (span.getSpanContext().isValid()) { + io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes); + if (otelContext != null) { + Span span = Span.fromContext(otelContext); tracer().onRequest(span, context.httpRequest()); SdkRequestDecorator decorator = decorator(executionAttributes); if (decorator != null) { @@ -145,12 +146,13 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor { @Override public void afterExecution( Context.AfterExecution context, ExecutionAttributes executionAttributes) { - Span span = getSpanFromAttributes(executionAttributes); - if (span.getSpanContext().isValid()) { + io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes); + if (otelContext != null) { clearAttributes(executionAttributes); + Span span = Span.fromContext(otelContext); tracer().afterExecution(span, context.httpRequest()); onSdkResponse(span, context.response()); - tracer().end(span, context.httpResponse()); + tracer().end(otelContext, context.httpResponse()); } } @@ -163,10 +165,10 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor { @Override public void onExecutionFailure( Context.FailedExecution context, ExecutionAttributes executionAttributes) { - Span span = getSpanFromAttributes(executionAttributes); - if (span.getSpanContext().isValid()) { + io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes); + if (otelContext != null) { clearAttributes(executionAttributes); - tracer().endExceptionally(span, context.exception()); + tracer().endExceptionally(otelContext, context.exception()); } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy index a521b56954..74f913c065 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy @@ -80,30 +80,16 @@ class Elasticsearch6RestClientTest extends AgentTestRunner { result.status == "green" assertTraces(1) { - trace(0, 2) { + trace(0, 1) { span(0) { name "GET _cluster/health" kind CLIENT hasNoParent() attributes { - "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address - "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch" "${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health" - } - } - span(1) { - name expectedOperationName("GET") - kind CLIENT - childOf span(0) - attributes { - "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" - "${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1" - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" - "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 + "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address + "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port } } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/Elasticsearch5RestClientInstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/Elasticsearch5RestClientInstrumentationModule.java index 92d2a4dd88..1358f1d5d4 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/Elasticsearch5RestClientInstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v5_0/Elasticsearch5RestClientInstrumentationModule.java @@ -71,7 +71,6 @@ public class Elasticsearch5RestClientInstrumentationModule extends Instrumentati span = tracer().startSpan(null, method + " " + endpoint); scope = tracer().startScope(span); - tracer().onRequest(span, method, endpoint); responseListener = new RestResponseListener(responseListener, span); } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/groovy/Elasticsearch5RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/groovy/Elasticsearch5RestClientTest.groovy index 8f9c8e3cfd..4a4ca73c35 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/groovy/Elasticsearch5RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/src/test/groovy/Elasticsearch5RestClientTest.groovy @@ -84,30 +84,16 @@ class Elasticsearch5RestClientTest extends AgentTestRunner { result.status == "green" assertTraces(1) { - trace(0, 2) { + trace(0, 1) { span(0) { name "GET _cluster/health" kind CLIENT hasNoParent() attributes { - "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address - "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch" "${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health" - } - } - span(1) { - name expectedOperationName("GET") - kind CLIENT - childOf span(0) - attributes { - "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" - "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 - "${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1" + "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address + "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port } } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy index e4cf53b7f9..f87dd05d9a 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy @@ -85,30 +85,16 @@ class Elasticsearch6RestClientTest extends AgentTestRunner { result.status == "green" assertTraces(1) { - trace(0, 2) { + trace(0, 1) { span(0) { name "GET _cluster/health" kind CLIENT hasNoParent() attributes { - "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address - "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch" "${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health" - } - } - span(1) { - name expectedOperationName("GET") - kind CLIENT - childOf span(0) - attributes { - "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" - "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 - "${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1" + "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address + "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port } } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/Elasticsearch6RestClientInstrumentationModule.java b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/Elasticsearch6RestClientInstrumentationModule.java index 87e54b901e..59c18ae072 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/Elasticsearch6RestClientInstrumentationModule.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/v6_4/Elasticsearch6RestClientInstrumentationModule.java @@ -69,7 +69,6 @@ public class Elasticsearch6RestClientInstrumentationModule extends Instrumentati span = tracer().startSpan(null, request.getMethod() + " " + request.getEndpoint()); scope = tracer().startScope(span); - tracer().onRequest(span, request.getMethod(), request.getEndpoint()); responseListener = new RestResponseListener(responseListener, span); } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/groovy/Elasticsearch6RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/groovy/Elasticsearch6RestClientTest.groovy index fac665d2d2..74f913c065 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/groovy/Elasticsearch6RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/src/test/groovy/Elasticsearch6RestClientTest.groovy @@ -80,30 +80,16 @@ class Elasticsearch6RestClientTest extends AgentTestRunner { result.status == "green" assertTraces(1) { - trace(0, 2) { + trace(0, 1) { span(0) { name "GET _cluster/health" kind CLIENT hasNoParent() attributes { - "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address - "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.DB_SYSTEM.key()}" "elasticsearch" "${SemanticAttributes.DB_OPERATION.key()}" "GET _cluster/health" - } - } - span(1) { - name expectedOperationName("GET") - kind CLIENT - childOf span(0) - attributes { - "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" - "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" - "${SemanticAttributes.HTTP_METHOD.key()}" "GET" - "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 - "${SemanticAttributes.HTTP_FLAVOR.key()}" "1.1" + "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address + "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port } } } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestClientTracer.java b/instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestClientTracer.java index 891cb767a8..1b62457f2e 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestClientTracer.java +++ b/instrumentation/elasticsearch/elasticsearch-rest-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/elasticsearch/rest/ElasticsearchRestClientTracer.java @@ -19,12 +19,6 @@ public class ElasticsearchRestClientTracer extends DatabaseClientTracer contextStore = InstrumentationContext.get(HttpRequest.class, Context.class); - Context context = contextStore.get(request); + context = contextStore.get(request); if (context == null) { - span = tracer().startSpan(request); - scope = tracer().startScope(span, request.getHeaders()); - // TODO (trask) ideally we could pass current context into startScope to avoid extra lookup - contextStore.put(request, Java8BytecodeBridge.currentContext()); + Context parentContext = currentContext(); + if (tracer().shouldStartSpan(parentContext)) { + context = tracer().startSpan(parentContext, request, request.getHeaders()); + contextStore.put(request, context); + scope = context.makeCurrent(); + } } else { // span was created by GoogleHttpClientAsyncAdvice instrumentation below - span = Java8BytecodeBridge.spanFromContext(context); scope = context.makeCurrent(); } } @@ -105,20 +106,22 @@ public class GoogleHttpClientInstrumentationModule extends InstrumentationModule public static void methodExit( @Advice.Return HttpResponse response, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } scope.close(); - if (throwable == null) { - tracer().end(span, response); + tracer().end(context, response); } else { - tracer().endExceptionally(span, response, throwable); + tracer().endExceptionally(context, response, throwable); } // If HttpRequest.setThrowExceptionOnExecuteError is set to false, there are no exceptions // for a failed request. Thus, check the response code if (response != null && !response.isSuccessStatusCode()) { - span.setStatus(StatusCode.ERROR); + spanFromContext(context).setStatus(StatusCode.ERROR); } } } @@ -128,28 +131,36 @@ public class GoogleHttpClientInstrumentationModule extends InstrumentationModule @Advice.OnMethodEnter(suppress = Throwable.class) public static void methodEnter( @Advice.This HttpRequest request, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } - span = tracer().startSpan(request); - scope = tracer().startScope(span, request.getHeaders()); + context = tracer().startSpan(parentContext, request, request.getHeaders()); // propagating the context manually here so this instrumentation will work with and without // the executors instrumentation ContextStore contextStore = InstrumentationContext.get(HttpRequest.class, Context.class); - contextStore.put(request, Java8BytecodeBridge.currentContext()); + contextStore.put(request, context); + + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } scope.close(); if (throwable != null) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); } } } diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java index 70fe54ac67..240c9bd6f3 100644 --- a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.httpurlconnection; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.httpurlconnection.HttpUrlConnectionTracer.tracer; import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass; import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf; @@ -17,7 +18,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; import io.opentelemetry.javaagent.instrumentation.api.ContextStore; @@ -79,7 +80,7 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul @Advice.OnMethodEnter(suppress = Throwable.class) public static HttpUrlState methodEnter( - @Advice.This HttpURLConnection thiz, + @Advice.This HttpURLConnection connection, @Advice.FieldValue("connected") boolean connected, @Advice.Local("otelScope") Scope scope) { @@ -90,22 +91,27 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul ContextStore contextStore = InstrumentationContext.get(HttpURLConnection.class, HttpUrlState.class); - HttpUrlState state = contextStore.putIfAbsent(thiz, HttpUrlState.FACTORY); + HttpUrlState state = contextStore.putIfAbsent(connection, HttpUrlState::new); synchronized (state) { - if (!state.hasSpan() && !state.isFinished()) { - Span span = state.start(thiz); - if (!connected) { - scope = tracer().startScope(span, thiz); + if (!state.initialized) { + Context parentContext = currentContext(); + if (tracer().shouldStartSpan(parentContext)) { + state.context = tracer().startSpan(parentContext, connection, connection); + if (!connected) { + scope = state.context.makeCurrent(); + } } + state.initialized = true; } - return state; } + return state; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Enter HttpUrlState state, + @Advice.This HttpURLConnection connection, @Advice.FieldValue("responseCode") int responseCode, @Advice.Thrown Throwable throwable, @Advice.Origin("#m") String methodName, @@ -120,62 +126,28 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul CallDepthThreadLocalMap.reset(HttpURLConnection.class); synchronized (state) { - if (state.hasSpan() && !state.isFinished()) { + if (state.context != null && !state.finished) { if (throwable != null) { - state.finishSpan(throwable); + tracer().endExceptionally(state.context, throwable); + state.finished = true; } else if ("getInputStream".equals(methodName)) { - state.finishSpan(responseCode); + // responseCode field is sometimes not populated. + // We can't call getResponseCode() due to some unwanted side-effects + // (e.g. breaks getOutputStream). + if (responseCode > 0) { + tracer().end(state.context, new HttpUrlResponse(connection, responseCode)); + state.finished = true; + } } } } } } + // state is always accessed under synchronized block public static class HttpUrlState { - - public static final ContextStore.Factory FACTORY = - new ContextStore.Factory() { - @Override - public HttpUrlState create() { - return new HttpUrlState(); - } - }; - - private volatile Span span = null; - private volatile boolean finished = false; - - public Span start(HttpURLConnection connection) { - span = tracer().startSpan(connection); - return span; - } - - public boolean hasSpan() { - return span != null; - } - - public boolean isFinished() { - return finished; - } - - public void finishSpan(Throwable throwable) { - tracer().endExceptionally(span, throwable); - span = null; - finished = true; - } - - public void finishSpan(int responseCode) { - /* - * responseCode field is sometimes not populated. - * We can't call getResponseCode() due to some unwanted side-effects - * (e.g. breaks getOutputStream). - */ - if (responseCode > 0) { - // Need to explicitly cast to boxed type to make sure correct method is called. - // https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/946 - tracer().end(span, (Integer) responseCode); - span = null; - finished = true; - } - } + public boolean initialized; + public Context context; + public boolean finished; } } diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTracer.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTracer.java index aac7d9a572..ff16266a4c 100644 --- a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTracer.java +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTracer.java @@ -14,7 +14,7 @@ import java.net.URI; import java.net.URISyntaxException; public class HttpUrlConnectionTracer - extends HttpClientTracer { + extends HttpClientTracer { private static final HttpUrlConnectionTracer TRACER = new HttpUrlConnectionTracer(); @@ -33,8 +33,8 @@ public class HttpUrlConnectionTracer } @Override - protected Integer status(Integer status) { - return status; + protected Integer status(HttpUrlResponse response) { + return response.status(); } @Override @@ -43,8 +43,8 @@ public class HttpUrlConnectionTracer } @Override - protected String responseHeader(Integer integer, String name) { - return null; + protected String responseHeader(HttpUrlResponse response, String name) { + return response.header(name); } @Override diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlResponse.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlResponse.java new file mode 100644 index 0000000000..53705d7524 --- /dev/null +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlResponse.java @@ -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); + } +} diff --git a/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/HttpClientInstrumentation.java b/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/HttpClientInstrumentation.java index 988ffbe43e..89d8e2fc93 100644 --- a/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/HttpClientInstrumentation.java +++ b/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/HttpClientInstrumentation.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.httpclient; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.httpclient.JdkHttpClientTracer.tracer; import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed; import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass; @@ -16,9 +17,8 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.net.http.HttpRequest; import java.net.http.HttpResponse; @@ -72,34 +72,32 @@ public class HttpClientInstrumentation implements TypeInstrumentation { @Advice.OnMethodEnter(suppress = Throwable.class) public static void methodEnter( @Advice.Argument(value = 0) HttpRequest httpRequest, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { - - callDepth = tracer().getCallDepth(); - if (callDepth.getAndIncrement() == 0) { - span = tracer().startSpan(httpRequest); - if (span.getSpanContext().isValid()) { - scope = tracer().startScope(span, httpRequest); - } + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } + + context = tracer().startSpan(parentContext, httpRequest, httpRequest); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Return HttpResponse result, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } - if (callDepth.decrementAndGet() == 0 && scope != null) { - scope.close(); - if (throwable == null) { - tracer().end(span, result); - } else { - tracer().endExceptionally(span, result, throwable); - } + scope.close(); + if (throwable == null) { + tracer().end(context, result); + } else { + tracer().endExceptionally(context, result, throwable); } } } @@ -109,34 +107,32 @@ public class HttpClientInstrumentation implements TypeInstrumentation { @Advice.OnMethodEnter(suppress = Throwable.class) public static void methodEnter( @Advice.Argument(value = 0) HttpRequest httpRequest, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { - - callDepth = tracer().getCallDepth(); - if (callDepth.getAndIncrement() == 0) { - span = tracer().startSpan(httpRequest); - if (span.getSpanContext().isValid()) { - scope = tracer().startScope(span, httpRequest); - } + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } + + context = tracer().startSpan(parentContext, httpRequest, httpRequest); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Return(readOnly = false) CompletableFuture> future, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } - if (callDepth.decrementAndGet() == 0 && scope != null) { - scope.close(); - if (throwable != null) { - tracer().endExceptionally(span, null, throwable); - } else { - future = future.whenComplete(new ResponseConsumer(span)); - } + scope.close(); + if (throwable != null) { + tracer().endExceptionally(context, null, throwable); + } else { + future = future.whenComplete(new ResponseConsumer(context)); } } } diff --git a/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/JdkHttpClientTracer.java b/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/JdkHttpClientTracer.java index bc9eedd7bd..46c667f534 100644 --- a/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/JdkHttpClientTracer.java +++ b/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/JdkHttpClientTracer.java @@ -11,10 +11,7 @@ import io.opentelemetry.api.trace.attributes.SemanticAttributes; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import java.net.URI; -import java.net.http.HttpClient; import java.net.http.HttpClient.Version; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; @@ -33,10 +30,6 @@ public class JdkHttpClientTracer return TRACER; } - public Depth getCallDepth() { - return CallDepthThreadLocalMap.getCallDepth(HttpClient.class); - } - @Override protected String getInstrumentationName() { return "io.opentelemetry.javaagent.java-httpclient"; diff --git a/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/ResponseConsumer.java b/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/ResponseConsumer.java index 21c7efc3e3..fce963a6d7 100644 --- a/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/ResponseConsumer.java +++ b/instrumentation/java-httpclient/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/ResponseConsumer.java @@ -7,23 +7,23 @@ package io.opentelemetry.javaagent.instrumentation.httpclient; import static io.opentelemetry.javaagent.instrumentation.httpclient.JdkHttpClientTracer.tracer; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import java.net.http.HttpResponse; import java.util.function.BiConsumer; public class ResponseConsumer implements BiConsumer, Throwable> { - private final Span span; + private final Context context; - public ResponseConsumer(Span span) { - this.span = span; + public ResponseConsumer(Context context) { + this.context = context; } @Override public void accept(HttpResponse httpResponse, Throwable throwable) { if (throwable == null) { - tracer().end(span, httpResponse); + tracer().end(context, httpResponse); } else { - tracer().endExceptionally(span, httpResponse, throwable); + tracer().endExceptionally(context, httpResponse, throwable); } } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java b/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java index 66fa3f38f4..c8d2f3cee3 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java +++ b/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1; import static io.opentelemetry.instrumentation.api.tracer.HttpServerTracer.CONTEXT_ATTRIBUTE; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1.JaxRsClientV1Tracer.tracer; import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed; import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass; @@ -17,10 +18,9 @@ import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import com.sun.jersey.api.client.ClientHandler; import com.sun.jersey.api.client.ClientRequest; import com.sun.jersey.api.client.ClientResponse; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; @@ -69,15 +69,14 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule { @Advice.OnMethodEnter public static void onEnter( @Advice.Argument(0) ClientRequest request, - @Advice.This ClientHandler thisObj, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { - // WARNING: this might be a chain...so we only have to trace the first in the chain. boolean isRootClientHandler = null == request.getProperties().get(CONTEXT_ATTRIBUTE); - if (isRootClientHandler) { - span = tracer().startSpan(request); - scope = tracer().startScope(span, request); + Context parentContext = currentContext(); + if (isRootClientHandler && tracer().shouldStartSpan(parentContext)) { + context = tracer().startSpan(parentContext, request, request); + scope = context.makeCurrent(); } } @@ -85,16 +84,17 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule { public static void onExit( @Advice.Return ClientResponse response, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { - if (scope != null) { - scope.close(); + if (scope == null) { + return; } + scope.close(); if (throwable != null) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); } else { - tracer().end(span, response); + tracer().end(context, response); } } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientTracingFilter.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientTracingFilter.java index 83c36725a9..4a5d41ac60 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientTracingFilter.java +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientTracingFilter.java @@ -7,8 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JaxRsClientTracer.tracer; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Scope; +import io.opentelemetry.context.Context; import javax.annotation.Priority; import javax.ws.rs.Priorities; import javax.ws.rs.client.ClientRequestContext; @@ -18,23 +17,23 @@ import javax.ws.rs.client.ClientResponseFilter; @Priority(Priorities.HEADER_DECORATOR) public class ClientTracingFilter implements ClientRequestFilter, ClientResponseFilter { - public static final String SPAN_PROPERTY_NAME = "io.opentelemetry.auto.jax-rs-client.span"; + public static final String CONTEXT_PROPERTY_NAME = "io.opentelemetry.auto.jax-rs-client.context"; @Override public void filter(ClientRequestContext requestContext) { - Span span = tracer().startSpan(requestContext); - // TODO (trask) expose inject separate from startScope, e.g. for async cases - Scope scope = tracer().startScope(span, requestContext); - scope.close(); - requestContext.setProperty(SPAN_PROPERTY_NAME, span); + Context parentContext = Context.current(); + if (tracer().shouldStartSpan(parentContext)) { + Context context = tracer().startSpan(parentContext, requestContext, requestContext); + requestContext.setProperty(CONTEXT_PROPERTY_NAME, context); + } } @Override public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) { - Object spanObj = requestContext.getProperty(SPAN_PROPERTY_NAME); - if (spanObj instanceof Span) { - Span span = (Span) spanObj; - tracer().end(span, responseContext); + Object contextObj = requestContext.getProperty(CONTEXT_PROPERTY_NAME); + if (contextObj instanceof Context) { + Context context = (Context) contextObj; + tracer().end(context, responseContext); } } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java index 89a44c9be5..f0a6e18f54 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java @@ -12,7 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.util.Collections; @@ -71,9 +71,9 @@ public class JerseyClientInstrumentationModule extends InstrumentationModule { @Advice.FieldValue("requestContext") ClientRequest context, @Advice.Thrown Throwable throwable) { if (throwable != null) { - Object prop = context.getProperty(ClientTracingFilter.SPAN_PROPERTY_NAME); - if (prop instanceof Span) { - tracer().endExceptionally((Span) prop, throwable); + Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME); + if (prop instanceof Context) { + tracer().endExceptionally((Context) prop, throwable); } } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/WrappedFuture.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/WrappedFuture.java index 2ebe4e6efb..60c1c5c4c4 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/WrappedFuture.java +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/WrappedFuture.java @@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JaxRsClientTracer.tracer; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -44,9 +44,9 @@ public class WrappedFuture implements Future { try { return wrapped.get(); } catch (ExecutionException e) { - Object prop = context.getProperty(ClientTracingFilter.SPAN_PROPERTY_NAME); - if (prop instanceof Span) { - tracer().endExceptionally((Span) prop, e.getCause()); + Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME); + if (prop instanceof Context) { + tracer().endExceptionally((Context) prop, e.getCause()); } throw e; } @@ -58,9 +58,9 @@ public class WrappedFuture implements Future { try { return wrapped.get(timeout, unit); } catch (ExecutionException e) { - Object prop = context.getProperty(ClientTracingFilter.SPAN_PROPERTY_NAME); - if (prop instanceof Span) { - tracer().endExceptionally((Span) prop, e.getCause()); + Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME); + if (prop instanceof Context) { + tracer().endExceptionally((Context) prop, e.getCause()); } throw e; } diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-resteasy-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ResteasyClientInstrumentationModule.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-resteasy-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ResteasyClientInstrumentationModule.java index c23841f685..6d0aa324db 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-resteasy-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ResteasyClientInstrumentationModule.java +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-resteasy-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ResteasyClientInstrumentationModule.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.ResteasyClientTracer.tracer; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; @@ -14,7 +15,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; @@ -67,25 +68,30 @@ public class ResteasyClientInstrumentationModule extends InstrumentationModule { @Advice.OnMethodEnter(suppress = Throwable.class) public static void methodEnter( @Advice.This ClientInvocation invocation, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { - span = tracer().startSpan(invocation); - scope = tracer().startScope(span, invocation); + Context parentContext = currentContext(); + if (tracer().shouldStartSpan(parentContext)) { + context = tracer().startSpan(parentContext, invocation, invocation); + scope = context.makeCurrent(); + } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Return Response response, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } scope.close(); - if (throwable != null) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); } else { - tracer().end(span, response); + tracer().end(context, response); } } } diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcTracer.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcTracer.java index 12710fe425..cddc44883d 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcTracer.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcTracer.java @@ -10,8 +10,8 @@ import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcUtils.normaliz import io.opentelemetry.api.trace.Span; import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer; +import io.opentelemetry.javaagent.instrumentation.api.CallDepth; import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import io.opentelemetry.javaagent.instrumentation.api.db.SqlStatementInfo; import java.net.InetSocketAddress; import java.sql.Connection; @@ -62,7 +62,7 @@ public class JdbcTracer extends DatabaseClientTracer { return info.getShortUrl(); } - public Depth getCallDepth() { + public CallDepth getCallDepth() { return CallDepthThreadLocalMap.getCallDepth(Statement.class); } diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java index 39f112f4c8..b303833edc 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -16,7 +16,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; +import io.opentelemetry.javaagent.instrumentation.api.CallDepth; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.sql.PreparedStatement; import java.util.Map; @@ -51,7 +51,7 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation { @Advice.This PreparedStatement statement, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelCallDepth") CallDepth callDepth) { callDepth = tracer().getCallDepth(); if (callDepth.getAndIncrement() == 0) { @@ -67,7 +67,7 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation { @Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelCallDepth") CallDepth callDepth) { if (callDepth.decrementAndGet() == 0 && scope != null) { scope.close(); if (throwable == null) { diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java index 45b630edf9..3644abe6ea 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java @@ -16,7 +16,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; +import io.opentelemetry.javaagent.instrumentation.api.CallDepth; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; import java.sql.Statement; import java.util.Map; @@ -52,7 +52,7 @@ public class StatementInstrumentation implements TypeInstrumentation { @Advice.This Statement statement, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelCallDepth") CallDepth callDepth) { callDepth = tracer().getCallDepth(); if (callDepth.getAndIncrement() == 0) { @@ -68,7 +68,7 @@ public class StatementInstrumentation implements TypeInstrumentation { @Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelCallDepth") CallDepth callDepth) { if (callDepth.decrementAndGet() == 0 && scope != null) { scope.close(); if (throwable == null) { diff --git a/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpAdvice.java b/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpAdvice.java index b0c88feb15..be01577594 100644 --- a/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpAdvice.java +++ b/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpAdvice.java @@ -5,12 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.khttp; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.khttp.KHttpHeadersInjectAdapter.asWritable; import static io.opentelemetry.javaagent.instrumentation.khttp.KHttpTracer.tracer; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import java.util.Map; import khttp.responses.Response; import net.bytebuddy.asm.Advice; @@ -22,34 +22,33 @@ public class KHttpAdvice { @Advice.Argument(value = 0) String method, @Advice.Argument(value = 1) String uri, @Advice.Argument(value = 2, readOnly = false) Map headers, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { - - callDepth = tracer().getCallDepth(); - if (callDepth.getAndIncrement() == 0) { - span = tracer().startSpan(new RequestWrapper(method, uri, headers)); - if (span.getSpanContext().isValid()) { - headers = asWritable(headers); - scope = tracer().startScope(span, headers); - } + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; } + + headers = asWritable(headers); + context = tracer().startSpan(parentContext, new RequestWrapper(method, uri, headers), headers); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Return Response response, @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { - if (callDepth.decrementAndGet() == 0 && scope != null) { - scope.close(); - if (throwable == null) { - tracer().end(span, response); - } else { - tracer().endExceptionally(span, response, throwable); - } + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + if (throwable == null) { + tracer().end(context, response); + } else { + tracer().endExceptionally(context, response, throwable); } } } diff --git a/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpTracer.java b/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpTracer.java index 124c70cfc2..d25b301ce3 100644 --- a/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpTracer.java +++ b/instrumentation/khttp-0.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/khttp/KHttpTracer.java @@ -9,12 +9,9 @@ import static io.opentelemetry.javaagent.instrumentation.khttp.KHttpHeadersInjec import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; -import khttp.KHttp; import khttp.responses.Response; public class KHttpTracer extends HttpClientTracer, Response> { @@ -24,10 +21,6 @@ public class KHttpTracer extends HttpClientTracer SERVER_SPAN = attributeKey(AttributeKeys.class.getName() + ".server-span"); - public static final AttributeKey CLIENT_SPAN = + public static final AttributeKey CLIENT_SPAN = attributeKey(AttributeKeys.class.getName() + ".client-span"); public static final AttributeKey CLIENT_PARENT_CONTEXT = diff --git a/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientRequestTracingHandler.java b/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientRequestTracingHandler.java index 718910843e..b083e776fc 100644 --- a/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientRequestTracingHandler.java +++ b/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientRequestTracingHandler.java @@ -27,30 +27,31 @@ public class HttpClientRequestTracingHandler extends ChannelOutboundHandlerAdapt return; } - // TODO pass Context into Tracer.startSpan() and then don't need this scoping - Scope parentScope = null; Context parentContext = ctx.channel().attr(AttributeKeys.CONNECT_CONTEXT).getAndRemove(); - if (parentContext != null) { - parentScope = parentContext.makeCurrent(); + if (parentContext == null) { + parentContext = Context.current(); + } + + if (!tracer().shouldStartSpan(parentContext)) { + ctx.write(msg, prm); + return; } HttpRequest request = (HttpRequest) msg; - ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(Context.current()); + ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(parentContext); - Span span = tracer().startSpan(request); - NetPeerUtils.INSTANCE.setNetPeer(span, (InetSocketAddress) ctx.channel().remoteAddress()); - ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(span); + Context context = tracer().startSpan(parentContext, request, request.headers()); + // TODO (trask) move this setNetPeer() call into the Tracer + NetPeerUtils.INSTANCE.setNetPeer( + Span.fromContext(context), (InetSocketAddress) ctx.channel().remoteAddress()); + ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(context); - try (Scope scope = tracer().startScope(span, request.headers())) { + try (Scope ignored = context.makeCurrent()) { ctx.write(msg, prm); } catch (Throwable throwable) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); throw throwable; - } finally { - if (null != parentScope) { - parentScope.close(); - } } } } diff --git a/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientResponseTracingHandler.java b/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientResponseTracingHandler.java index 370557aaf1..b4f73c6cf4 100644 --- a/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientResponseTracingHandler.java +++ b/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/HttpClientResponseTracingHandler.java @@ -11,7 +11,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.HttpResponse; import io.netty.util.Attribute; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.instrumentation.netty.v4_0.AttributeKeys; @@ -22,12 +21,12 @@ public class HttpClientResponseTracingHandler extends ChannelInboundHandlerAdapt public void channelRead(ChannelHandlerContext ctx, Object msg) { Attribute parentAttr = ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT); Context parentContext = parentAttr.get(); - Span span = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get(); + Context context = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get(); boolean finishSpan = msg instanceof HttpResponse; - if (span != null && finishSpan) { - tracer().end(span, (HttpResponse) msg); + if (context != null && finishSpan) { + tracer().end(context, (HttpResponse) msg); } // We want the callback in the scope of the parent, not the client span diff --git a/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/NettyHttpClientTracer.java b/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/NettyHttpClientTracer.java index aabf6ddbfb..8217a79e48 100644 --- a/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/NettyHttpClientTracer.java +++ b/instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/client/NettyHttpClientTracer.java @@ -11,9 +11,6 @@ import static io.opentelemetry.javaagent.instrumentation.netty.v4_0.client.Netty import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; import java.net.URI; @@ -28,20 +25,6 @@ public class NettyHttpClientTracer return TRACER; } - @Override - public Scope startScope(Span span, HttpHeaders headers) { - if (!headers.contains("amz-sdk-invocation-id")) { - return super.startScope(span, headers); - } else { - // TODO (trask) if we move injection up to aws-sdk layer, and start suppressing nested netty - // spans, do we still need this condition? - // AWS calls are often signed, so we can't add headers without breaking the signature. - Context context = Context.current().with(span); - context = context.with(CONTEXT_CLIENT_SPAN_KEY, span); - return context.makeCurrent(); - } - } - @Override protected String method(HttpRequest httpRequest) { return httpRequest.getMethod().name(); diff --git a/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/AttributeKeys.java b/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/AttributeKeys.java index a122ab733b..d3f5b920af 100644 --- a/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/AttributeKeys.java +++ b/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/AttributeKeys.java @@ -6,7 +6,6 @@ package io.opentelemetry.javaagent.instrumentation.netty.v4_1; import io.netty.util.AttributeKey; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; public class AttributeKeys { @@ -20,7 +19,7 @@ public class AttributeKeys { public static final AttributeKey SERVER_SPAN = AttributeKey.valueOf(AttributeKeys.class, "server-span"); - public static final AttributeKey CLIENT_SPAN = + public static final AttributeKey CLIENT_SPAN = AttributeKey.valueOf(AttributeKeys.class, "client-span"); public static final AttributeKey CLIENT_PARENT_CONTEXT = diff --git a/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientRequestTracingHandler.java b/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientRequestTracingHandler.java index a13d62defc..5063e3fe49 100644 --- a/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientRequestTracingHandler.java +++ b/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientRequestTracingHandler.java @@ -26,31 +26,32 @@ public class HttpClientRequestTracingHandler extends ChannelOutboundHandlerAdapt ctx.write(msg, prm); return; } - - // TODO pass Context into Tracer.startSpan() and then don't need this scoping - Scope parentScope = null; - Context parentContext = ctx.channel().attr(AttributeKeys.CONNECT_CONTEXT).getAndRemove(); - if (parentContext != null) { - parentScope = parentContext.makeCurrent(); - } - HttpRequest request = (HttpRequest) msg; - ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(Context.current()); + Context parentContext = ctx.channel().attr(AttributeKeys.CONNECT_CONTEXT).getAndRemove(); + if (parentContext == null) { + parentContext = Context.current(); + } - Span span = tracer().startSpan(request); - NetPeerUtils.INSTANCE.setNetPeer(span, (InetSocketAddress) ctx.channel().remoteAddress()); - ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(span); - - try (Scope ignored = tracer().startScope(span, request.headers())) { + if (!tracer().shouldStartSpan(parentContext)) { ctx.write(msg, prm); + return; + } + + ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(parentContext); + + Context context = tracer().startSpan(parentContext, request, request.headers()); + // TODO (trask) move this setNetPeer() call into the Tracer + NetPeerUtils.INSTANCE.setNetPeer( + Span.fromContext(context), (InetSocketAddress) ctx.channel().remoteAddress()); + ctx.channel().attr(AttributeKeys.CLIENT_SPAN).set(context); + + try (Scope ignored = context.makeCurrent()) { + ctx.write(msg, prm); + // span is ended normally in HttpClientResponseTracingHandler } catch (Throwable throwable) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); throw throwable; - } finally { - if (null != parentScope) { - parentScope.close(); - } } } } diff --git a/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientResponseTracingHandler.java b/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientResponseTracingHandler.java index 959e3b0a7e..4e5bc5b7df 100644 --- a/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientResponseTracingHandler.java +++ b/instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/client/HttpClientResponseTracingHandler.java @@ -11,7 +11,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.HttpResponse; import io.netty.util.Attribute; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.instrumentation.netty.v4_1.AttributeKeys; @@ -22,12 +21,12 @@ public class HttpClientResponseTracingHandler extends ChannelInboundHandlerAdapt public void channelRead(ChannelHandlerContext ctx, Object msg) { Attribute parentAttr = ctx.channel().attr(AttributeKeys.CLIENT_PARENT_CONTEXT); Context parentContext = parentAttr.get(); - Span span = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get(); + Context context = ctx.channel().attr(AttributeKeys.CLIENT_SPAN).get(); boolean finishSpan = msg instanceof HttpResponse; - if (span != null && finishSpan) { - tracer().end(span, (HttpResponse) msg); + if (context != null && finishSpan) { + tracer().end(context, (HttpResponse) msg); } // We want the callback in the scope of the parent, not the client span diff --git a/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/TracingInterceptor.java b/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/TracingInterceptor.java index 8d263d4cdc..63ef1f7082 100644 --- a/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/TracingInterceptor.java +++ b/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/TracingInterceptor.java @@ -10,24 +10,29 @@ import static io.opentelemetry.javaagent.instrumentation.okhttp.v2_2.OkHttpClien import com.squareup.okhttp.Interceptor; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.io.IOException; public class TracingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { - Span span = tracer().startSpan(chain.request()); + Context parentContext = Context.current(); + if (!tracer().shouldStartSpan(parentContext)) { + return chain.proceed(chain.request()); + } + Request.Builder requestBuilder = chain.request().newBuilder(); + Context context = tracer().startSpan(parentContext, chain.request(), requestBuilder); Response response; - try (Scope scope = tracer().startScope(span, requestBuilder)) { + try (Scope ignored = context.makeCurrent()) { response = chain.proceed(requestBuilder.build()); } catch (Exception e) { - tracer().endExceptionally(span, e); + tracer().endExceptionally(context, e); throw e; } - tracer().end(span, response); + tracer().end(context, response); return response; } } diff --git a/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/TracingInterceptor.java b/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/TracingInterceptor.java index 24887c40fe..599800b587 100644 --- a/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/TracingInterceptor.java +++ b/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/TracingInterceptor.java @@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.okhttp.v3_0; import static io.opentelemetry.javaagent.instrumentation.okhttp.v3_0.OkHttpClientTracer.tracer; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.io.IOException; import okhttp3.Interceptor; @@ -18,17 +18,22 @@ public class TracingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { - Span span = tracer().startSpan(chain.request()); + Context parentContext = Context.current(); + if (!tracer().shouldStartSpan(parentContext)) { + return chain.proceed(chain.request()); + } + + Request.Builder requestBuilder = chain.request().newBuilder(); + Context context = tracer().startSpan(parentContext, chain.request(), requestBuilder); Response response; - Request.Builder requestBuilder = chain.request().newBuilder(); - try (Scope ignored = tracer().startScope(span, requestBuilder)) { + try (Scope ignored = context.makeCurrent()) { response = chain.proceed(requestBuilder.build()); } catch (Exception e) { - tracer().endExceptionally(span, e); + tracer().endExceptionally(context, e); throw e; } - tracer().end(span, response); + tracer().end(context, response); return response; } } diff --git a/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/AsyncHandlerWrapper.java b/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/AsyncHandlerWrapper.java index effaa5a133..e884bfad97 100644 --- a/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/AsyncHandlerWrapper.java +++ b/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/AsyncHandlerWrapper.java @@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.playws.v1_0; import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import play.shaded.ahc.org.asynchttpclient.AsyncHandler; @@ -18,15 +17,15 @@ import play.shaded.ahc.org.asynchttpclient.Response; public class AsyncHandlerWrapper implements AsyncHandler { private final AsyncHandler delegate; - private final Span span; - private final Context invocationContext; + private final Context context; + private final Context parentContext; private final Response.ResponseBuilder builder = new Response.ResponseBuilder(); - public AsyncHandlerWrapper(AsyncHandler delegate, Span span, Context invocationContext) { + public AsyncHandlerWrapper(AsyncHandler delegate, Context context, Context parentContext) { this.delegate = delegate; - this.span = span; - this.invocationContext = invocationContext; + this.context = context; + this.parentContext = parentContext; } @Override @@ -50,20 +49,18 @@ public class AsyncHandlerWrapper implements AsyncHandler { @Override public Object onCompleted() throws Exception { - Response response = builder.build(); - tracer().end(span, response); + tracer().end(context, builder.build()); - try (Scope scope = invocationContext.makeCurrent()) { + try (Scope scope = parentContext.makeCurrent()) { return delegate.onCompleted(); } } @Override public void onThrowable(Throwable throwable) { - tracer().endExceptionally(span, throwable); - span.end(); + tracer().endExceptionally(context, throwable); - try (Scope scope = invocationContext.makeCurrent()) { + try (Scope scope = parentContext.makeCurrent()) { delegate.onThrowable(throwable); } } diff --git a/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java b/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java index 45e5d5414d..7ee1e8158e 100644 --- a/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java +++ b/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/PlayWsInstrumentationModule.java @@ -5,14 +5,13 @@ package io.opentelemetry.javaagent.instrumentation.playws.v1_0; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer; import static java.util.Collections.singletonList; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; @@ -39,32 +38,38 @@ public class PlayWsInstrumentationModule extends InstrumentationModule { public static void methodEnter( @Advice.Argument(0) Request request, @Advice.Argument(value = 1, readOnly = false) AsyncHandler asyncHandler, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { - Context parentContext = Java8BytecodeBridge.currentContext(); + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } - span = tracer().startSpan(request); - scope = tracer().startScope(span, request.getHeaders()); + context = tracer().startSpan(parentContext, request, request.getHeaders()); + scope = context.makeCurrent(); if (asyncHandler instanceof StreamedAsyncHandler) { asyncHandler = new StreamedAsyncHandlerWrapper( - (StreamedAsyncHandler) asyncHandler, span, parentContext); + (StreamedAsyncHandler) asyncHandler, context, parentContext); } else if (!(asyncHandler instanceof WebSocketUpgradeHandler)) { // websocket upgrade handlers aren't supported - asyncHandler = new AsyncHandlerWrapper(asyncHandler, span, parentContext); + asyncHandler = new AsyncHandlerWrapper(asyncHandler, context, parentContext); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( @Advice.Thrown Throwable throwable, - @Advice.Local("otelSpan") Span span, + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } scope.close(); if (throwable != null) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); } } } diff --git a/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/StreamedAsyncHandlerWrapper.java b/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/StreamedAsyncHandlerWrapper.java index c8953bff4b..123d6320ee 100644 --- a/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/StreamedAsyncHandlerWrapper.java +++ b/instrumentation/play-ws/play-ws-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v1_0/StreamedAsyncHandlerWrapper.java @@ -5,7 +5,6 @@ package io.opentelemetry.javaagent.instrumentation.playws.v1_0; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import org.reactivestreams.Publisher; import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler; @@ -15,8 +14,8 @@ public class StreamedAsyncHandlerWrapper extends AsyncHandlerWrapper private final StreamedAsyncHandler streamedDelegate; public StreamedAsyncHandlerWrapper( - StreamedAsyncHandler delegate, Span span, Context invocationContext) { - super(delegate, span, invocationContext); + StreamedAsyncHandler delegate, Context context, Context parentContext) { + super(delegate, context, parentContext); streamedDelegate = delegate; } diff --git a/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/AsyncHandlerWrapper.java b/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/AsyncHandlerWrapper.java index b0422cc93a..a60f198af4 100644 --- a/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/AsyncHandlerWrapper.java +++ b/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/AsyncHandlerWrapper.java @@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_0; import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.net.InetSocketAddress; @@ -22,15 +21,15 @@ import play.shaded.ahc.org.asynchttpclient.netty.request.NettyRequest; public class AsyncHandlerWrapper implements AsyncHandler { private final AsyncHandler delegate; - private final Span span; + private final Context context; private final Context parentContext; private final Response.ResponseBuilder builder = new Response.ResponseBuilder(); - public AsyncHandlerWrapper(AsyncHandler delegate, Span span) { + public AsyncHandlerWrapper(AsyncHandler delegate, Context context, Context parentContext) { this.delegate = delegate; - this.span = span; - parentContext = Context.current(); + this.context = context; + this.parentContext = parentContext; } @Override @@ -55,7 +54,7 @@ public class AsyncHandlerWrapper implements AsyncHandler { @Override public Object onCompleted() throws Exception { Response response = builder.build(); - tracer().end(span, response); + tracer().end(context, response); try (Scope ignored = parentContext.makeCurrent()) { return delegate.onCompleted(); @@ -64,7 +63,7 @@ public class AsyncHandlerWrapper implements AsyncHandler { @Override public void onThrowable(Throwable throwable) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); try (Scope ignored = parentContext.makeCurrent()) { delegate.onThrowable(throwable); diff --git a/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java b/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java index 1fa9ebb209..32c1f3da9a 100644 --- a/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java +++ b/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/PlayWsInstrumentationModule.java @@ -5,12 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_0; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer; import static java.util.Collections.singletonList; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Scope; +import io.opentelemetry.context.Context; import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; @@ -37,28 +37,29 @@ public class PlayWsInstrumentationModule extends InstrumentationModule { public static void methodEnter( @Advice.Argument(0) Request request, @Advice.Argument(value = 1, readOnly = false) AsyncHandler asyncHandler, - @Advice.Local("otelSpan") Span span) { + @Advice.Local("otelContext") Context context) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } - span = tracer().startSpan(request); - // TODO (trask) expose inject separate from startScope, e.g. for async cases - Scope scope = tracer().startScope(span, request.getHeaders()); - scope.close(); + context = tracer().startSpan(parentContext, request, request.getHeaders()); if (asyncHandler instanceof StreamedAsyncHandler) { asyncHandler = - new StreamedAsyncHandlerWrapper((StreamedAsyncHandler) asyncHandler, span); + new StreamedAsyncHandlerWrapper( + (StreamedAsyncHandler) asyncHandler, context, parentContext); } else if (!(asyncHandler instanceof WebSocketUpgradeHandler)) { // websocket upgrade handlers aren't supported - asyncHandler = new AsyncHandlerWrapper(asyncHandler, span); + asyncHandler = new AsyncHandlerWrapper(asyncHandler, context, parentContext); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( - @Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span) { - - if (throwable != null) { - tracer().endExceptionally(span, throwable); + @Advice.Thrown Throwable throwable, @Advice.Local("otelContext") Context context) { + if (context != null && throwable != null) { + tracer().endExceptionally(context, throwable); } } } diff --git a/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/StreamedAsyncHandlerWrapper.java b/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/StreamedAsyncHandlerWrapper.java index 1963e3af98..79208ed0ba 100644 --- a/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/StreamedAsyncHandlerWrapper.java +++ b/instrumentation/play-ws/play-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_0/StreamedAsyncHandlerWrapper.java @@ -5,7 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_0; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import org.reactivestreams.Publisher; import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler; @@ -13,8 +13,9 @@ public class StreamedAsyncHandlerWrapper extends AsyncHandlerWrapper implements StreamedAsyncHandler { private final StreamedAsyncHandler streamedDelegate; - public StreamedAsyncHandlerWrapper(StreamedAsyncHandler delegate, Span span) { - super(delegate, span); + public StreamedAsyncHandlerWrapper( + StreamedAsyncHandler delegate, Context context, Context parentContext) { + super(delegate, context, parentContext); streamedDelegate = delegate; } diff --git a/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/AsyncHandlerWrapper.java b/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/AsyncHandlerWrapper.java index e3bf596988..d553d45fcf 100644 --- a/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/AsyncHandlerWrapper.java +++ b/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/AsyncHandlerWrapper.java @@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_1; import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.net.InetSocketAddress; @@ -23,15 +22,15 @@ import play.shaded.ahc.org.asynchttpclient.netty.request.NettyRequest; public class AsyncHandlerWrapper implements AsyncHandler { private final AsyncHandler delegate; - private final Span span; + private final Context context; private final Context parentContext; private final Response.ResponseBuilder builder = new Response.ResponseBuilder(); - public AsyncHandlerWrapper(AsyncHandler delegate, Span span) { + public AsyncHandlerWrapper(AsyncHandler delegate, Context context, Context parentContext) { this.delegate = delegate; - this.span = span; - parentContext = Context.current(); + this.context = context; + this.parentContext = parentContext; } @Override @@ -56,7 +55,7 @@ public class AsyncHandlerWrapper implements AsyncHandler { @Override public Object onCompleted() throws Exception { Response response = builder.build(); - tracer().end(span, response); + tracer().end(context, response); try (Scope ignored = parentContext.makeCurrent()) { return delegate.onCompleted(); @@ -65,7 +64,7 @@ public class AsyncHandlerWrapper implements AsyncHandler { @Override public void onThrowable(Throwable throwable) { - tracer().endExceptionally(span, throwable); + tracer().endExceptionally(context, throwable); try (Scope ignored = parentContext.makeCurrent()) { delegate.onThrowable(throwable); diff --git a/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java b/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java index f86e5d9134..ab290f84f0 100644 --- a/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java +++ b/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/PlayWsInstrumentationModule.java @@ -5,12 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_1; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static io.opentelemetry.javaagent.instrumentation.playws.PlayWsClientTracer.tracer; import static java.util.Collections.singletonList; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Scope; +import io.opentelemetry.context.Context; import io.opentelemetry.javaagent.instrumentation.playws.AsyncHttpClientInstrumentation; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; @@ -37,28 +37,29 @@ public class PlayWsInstrumentationModule extends InstrumentationModule { public static void methodEnter( @Advice.Argument(0) Request request, @Advice.Argument(value = 1, readOnly = false) AsyncHandler asyncHandler, - @Advice.Local("otelSpan") Span span) { + @Advice.Local("otelContext") Context context) { + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } - span = tracer().startSpan(request); - // TODO (trask) expose inject separate from startScope, e.g. for async cases - Scope scope = tracer().startScope(span, request.getHeaders()); - scope.close(); + context = tracer().startSpan(parentContext, request, request.getHeaders()); if (asyncHandler instanceof StreamedAsyncHandler) { asyncHandler = - new StreamedAsyncHandlerWrapper((StreamedAsyncHandler) asyncHandler, span); + new StreamedAsyncHandlerWrapper( + (StreamedAsyncHandler) asyncHandler, context, parentContext); } else if (!(asyncHandler instanceof WebSocketUpgradeHandler)) { // websocket upgrade handlers aren't supported - asyncHandler = new AsyncHandlerWrapper(asyncHandler, span); + asyncHandler = new AsyncHandlerWrapper(asyncHandler, context, parentContext); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( - @Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span) { - - if (throwable != null) { - tracer().endExceptionally(span, throwable); + @Advice.Thrown Throwable throwable, @Advice.Local("otelContext") Context context) { + if (context != null && throwable != null) { + tracer().endExceptionally(context, throwable); } } } diff --git a/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/StreamedAsyncHandlerWrapper.java b/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/StreamedAsyncHandlerWrapper.java index 1f9190eb88..1c251177c7 100644 --- a/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/StreamedAsyncHandlerWrapper.java +++ b/instrumentation/play-ws/play-ws-2.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/playws/v2_1/StreamedAsyncHandlerWrapper.java @@ -5,7 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.playws.v2_1; -import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; import org.reactivestreams.Publisher; import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler; @@ -13,8 +13,9 @@ public class StreamedAsyncHandlerWrapper extends AsyncHandlerWrapper implements StreamedAsyncHandler { private final StreamedAsyncHandler streamedDelegate; - public StreamedAsyncHandlerWrapper(StreamedAsyncHandler delegate, Span span) { - super(delegate, span); + public StreamedAsyncHandlerWrapper( + StreamedAsyncHandler delegate, Context context, Context parentContext) { + super(delegate, context, parentContext); streamedDelegate = delegate; } diff --git a/instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/http/HttpServletResponseInstrumentationModule.java b/instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/http/HttpServletResponseInstrumentationModule.java index ea14410117..780e7931f2 100644 --- a/instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/http/HttpServletResponseInstrumentationModule.java +++ b/instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/http/HttpServletResponseInstrumentationModule.java @@ -16,8 +16,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.instrumentation.api.CallDepth; import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.tooling.InstrumentationModule; import io.opentelemetry.javaagent.tooling.TypeInstrumentation; @@ -65,7 +65,7 @@ public class HttpServletResponseInstrumentationModule extends InstrumentationMod @Advice.Origin Method method, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelCallDepth") CallDepth callDepth) { callDepth = CallDepthThreadLocalMap.getCallDepth(HttpServletResponse.class); // Don't want to generate a new top-level span if (callDepth.getAndIncrement() == 0 @@ -80,7 +80,7 @@ public class HttpServletResponseInstrumentationModule extends InstrumentationMod @Advice.Thrown Throwable throwable, @Advice.Local("otelSpan") Span span, @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") Depth callDepth) { + @Advice.Local("otelCallDepth") CallDepth callDepth) { if (callDepth.decrementAndGet() == 0 && span != null) { CallDepthThreadLocalMap.reset(HttpServletResponse.class); diff --git a/instrumentation/spring/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/httpclients/RestTemplateInterceptor.java b/instrumentation/spring/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/httpclients/RestTemplateInterceptor.java index a8e5e10eac..8119a8da24 100644 --- a/instrumentation/spring/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/httpclients/RestTemplateInterceptor.java +++ b/instrumentation/spring/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/httpclients/RestTemplateInterceptor.java @@ -7,8 +7,8 @@ package io.opentelemetry.instrumentation.spring.httpclients; import static io.opentelemetry.instrumentation.spring.httpclients.RestTemplateTracer.tracer; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.io.IOException; import org.springframework.http.HttpRequest; @@ -28,11 +28,15 @@ public final class RestTemplateInterceptor implements ClientHttpRequestIntercept @Override public ClientHttpResponse intercept( HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + Context parentContext = Context.current(); + if (!tracer().shouldStartSpan(parentContext)) { + return execution.execute(request, body); + } - Span span = tracer().startSpan(request); - try (Scope scope = tracer().startScope(span, request.getHeaders())) { + Context context = tracer().startSpan(parentContext, request, request.getHeaders()); + try (Scope ignored = context.makeCurrent()) { ClientHttpResponse response = execution.execute(request, body); - tracer().end(span, response); + tracer().end(context, response); return response; } } diff --git a/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/SpringWebfluxHttpClientTracer.java b/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/SpringWebfluxHttpClientTracer.java index d62e4dae0a..3458d9207f 100644 --- a/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/SpringWebfluxHttpClientTracer.java +++ b/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/SpringWebfluxHttpClientTracer.java @@ -9,6 +9,7 @@ import static io.opentelemetry.instrumentation.spring.webflux.client.HttpHeaders import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; import java.lang.invoke.MethodHandle; @@ -30,7 +31,8 @@ public class SpringWebfluxHttpClientTracer private static final MethodHandle RAW_STATUS_CODE = findRawStatusCode(); - public void onCancel(Span span) { + public void onCancel(Context context) { + Span span = Span.fromContext(context); span.setAttribute("event", "cancelled"); span.setAttribute("message", "The subscription was cancelled"); } diff --git a/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/TraceWebClientSubscriber.java b/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/TraceWebClientSubscriber.java index ae143a5d0c..eb82231632 100644 --- a/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/TraceWebClientSubscriber.java +++ b/instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/TraceWebClientSubscriber.java @@ -7,7 +7,6 @@ package io.opentelemetry.instrumentation.spring.webflux.client; import static io.opentelemetry.instrumentation.spring.webflux.client.SpringWebfluxHttpClientTracer.tracer; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; import org.reactivestreams.Subscription; import org.springframework.web.reactive.function.client.ClientResponse; @@ -23,15 +22,12 @@ public final class TraceWebClientSubscriber implements CoreSubscriber actual, - Span span, io.opentelemetry.context.Context tracingContext) { this.actual = actual; - this.span = span; this.tracingContext = tracingContext; this.context = actual.currentContext(); } @@ -46,7 +42,7 @@ public final class TraceWebClientSubscriber implements CoreSubscriber subscriber) { - Span span = tracer().startSpan(request); + Context parentContext = Context.current(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } + ClientRequest.Builder builder = ClientRequest.from(request); - try (Scope ignored = tracer().startScope(span, builder)) { + Context context = tracer().startSpan(parentContext, request, builder); + try (Scope ignored = context.makeCurrent()) { this.next .exchange(builder.build()) .doOnCancel( () -> { - tracer().onCancel(span); - tracer().end(span); + tracer().onCancel(context); + tracer().end(context); }) - .subscribe( - new TraceWebClientSubscriber( - subscriber, span, io.opentelemetry.context.Context.current())); + .subscribe(new TraceWebClientSubscriber(subscriber, context)); } } } diff --git a/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/CallDepth.java b/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/CallDepth.java new file mode 100644 index 0000000000..34b6d3fefa --- /dev/null +++ b/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/CallDepth.java @@ -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; + } +} diff --git a/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/CallDepthThreadLocalMap.java b/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/CallDepthThreadLocalMap.java index 7654724342..120e5a3d3e 100644 --- a/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/CallDepthThreadLocalMap.java +++ b/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/CallDepthThreadLocalMap.java @@ -30,7 +30,7 @@ public class CallDepthThreadLocalMap { } }; - public static Depth getCallDepth(Class k) { + public static CallDepth getCallDepth(Class k) { return TLS.get(k).get(); } @@ -43,29 +43,13 @@ public class CallDepthThreadLocalMap { } public static void reset(Class k) { - TLS.get(k).get().depth = 0; + TLS.get(k).get().reset(); } - public static final class Depth { - private int depth; - - private Depth() { - this.depth = 0; - } - - public int getAndIncrement() { - return this.depth++; - } - - public int decrementAndGet() { - return --this.depth; - } - } - - private static final class ThreadLocalDepth extends ThreadLocal { + private static final class ThreadLocalDepth extends ThreadLocal { @Override - protected Depth initialValue() { - return new Depth(); + protected CallDepth initialValue() { + return new CallDepth(); } } } diff --git a/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/SpanWithScope.java b/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/SpanWithScope.java index 209681ee35..266a475a14 100644 --- a/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/SpanWithScope.java +++ b/javaagent-api/src/main/java/io/opentelemetry/javaagent/instrumentation/api/SpanWithScope.java @@ -63,7 +63,7 @@ import io.opentelemetry.context.Scope; *
  • The new pattern is more efficient since it doesn't require instantiating the {@code * SpanWithScope} holder object *
  • 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 * * * @deprecated see above