Akka and Apache HttpClient migrate to decorators

This commit is contained in:
Tyler Benson 2019-02-20 09:47:35 -08:00
parent f251356df3
commit 13e708ec42
10 changed files with 227 additions and 107 deletions

View File

@ -69,6 +69,8 @@ class LagomTest extends AgentTestRunner {
"$Tags.HTTP_STATUS.key" 101 "$Tags.HTTP_STATUS.key" 101
"$Tags.HTTP_URL.key" "ws://localhost:${server.port()}/echo" "$Tags.HTTP_URL.key" "ws://localhost:${server.port()}/echo"
"$Tags.HTTP_METHOD.key" "GET" "$Tags.HTTP_METHOD.key" "GET"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" server.port()
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER "$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.COMPONENT.key" "akka-http-server" "$Tags.COMPONENT.key" "akka-http-server"
@ -107,6 +109,8 @@ class LagomTest extends AgentTestRunner {
"$Tags.HTTP_STATUS.key" 500 "$Tags.HTTP_STATUS.key" 500
"$Tags.HTTP_URL.key" "ws://localhost:${server.port()}/error" "$Tags.HTTP_URL.key" "ws://localhost:${server.port()}/error"
"$Tags.HTTP_METHOD.key" "GET" "$Tags.HTTP_METHOD.key" "GET"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" server.port()
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER "$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.COMPONENT.key" "akka-http-server" "$Tags.COMPONENT.key" "akka-http-server"

View File

@ -0,0 +1,49 @@
package datadog.trace.instrumentation.akkahttp;
import akka.http.scaladsl.model.HttpRequest;
import akka.http.scaladsl.model.HttpResponse;
import datadog.trace.agent.decorator.HttpClientDecorator;
public class AkkaHttpClientDecorator extends HttpClientDecorator<HttpRequest, HttpResponse> {
public static final AkkaHttpClientDecorator INSTANCE = new AkkaHttpClientDecorator();
@Override
protected String[] instrumentationNames() {
return new String[] {"akka-http", "akka-http-client"};
}
@Override
protected String component() {
return "akka-http-client";
}
@Override
protected String service() {
return null;
}
@Override
protected String method(final HttpRequest httpRequest) {
return httpRequest.method().value();
}
@Override
protected String url(final HttpRequest httpRequest) {
return httpRequest.uri().toString();
}
@Override
protected String hostname(final HttpRequest httpRequest) {
return httpRequest.getUri().host().address();
}
@Override
protected Integer port(final HttpRequest httpRequest) {
return httpRequest.getUri().port();
}
@Override
protected Integer status(final HttpResponse httpResponse) {
return httpResponse.status().intValue();
}
}

View File

@ -1,6 +1,5 @@
package datadog.trace.instrumentation.akkahttp; package datadog.trace.instrumentation.akkahttp;
import static io.opentracing.log.Fields.ERROR_OBJECT;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@ -13,18 +12,12 @@ import akka.http.scaladsl.model.HttpResponse;
import akka.stream.scaladsl.Flow; import akka.stream.scaladsl.Flow;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.Config;
import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags;
import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.bootstrap.CallDepthThreadLocalMap;
import io.opentracing.Scope; import io.opentracing.Scope;
import io.opentracing.Span; import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format; import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap; import io.opentracing.propagation.TextMap;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer; import io.opentracing.util.GlobalTracer;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
@ -55,12 +48,14 @@ public final class AkkaHttpClientInstrumentation extends Instrumenter.Default {
return new String[] { return new String[] {
AkkaHttpClientInstrumentation.class.getName() + "$OnCompleteHandler", AkkaHttpClientInstrumentation.class.getName() + "$OnCompleteHandler",
AkkaHttpClientInstrumentation.class.getName() + "$AkkaHttpHeaders", AkkaHttpClientInstrumentation.class.getName() + "$AkkaHttpHeaders",
AkkaHttpClientInstrumentation.class.getPackage().getName() + ".AkkaHttpClientTransformFlow", packageName + ".AkkaHttpClientTransformFlow",
AkkaHttpClientInstrumentation.class.getPackage().getName() + ".AkkaHttpClientTransformFlow$", packageName + ".AkkaHttpClientTransformFlow$",
AkkaHttpClientInstrumentation.class.getPackage().getName() packageName + ".AkkaHttpClientTransformFlow$$anonfun$transform$1",
+ ".AkkaHttpClientTransformFlow$$anonfun$transform$1", packageName + ".AkkaHttpClientTransformFlow$$anonfun$transform$2",
AkkaHttpClientInstrumentation.class.getPackage().getName() "datadog.trace.agent.decorator.BaseDecorator",
+ ".AkkaHttpClientTransformFlow$$anonfun$transform$2", "datadog.trace.agent.decorator.ClientDecorator",
"datadog.trace.agent.decorator.HttpClientDecorator",
packageName + ".AkkaHttpClientDecorator",
}; };
} }
@ -102,23 +97,9 @@ public final class AkkaHttpClientInstrumentation extends Instrumenter.Default {
return null; return null;
} }
final Tracer.SpanBuilder builder = final Scope scope = GlobalTracer.get().buildSpan("akka-http.request").startActive(false);
GlobalTracer.get() AkkaHttpClientDecorator.INSTANCE.afterStart(scope.span());
.buildSpan("akka-http.request") AkkaHttpClientDecorator.INSTANCE.onRequest(scope.span(), request);
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT)
.withTag(Tags.COMPONENT.getKey(), "akka-http-client");
if (request != null) {
builder
.withTag(Tags.HTTP_METHOD.getKey(), request.method().value())
.withTag(Tags.HTTP_URL.getKey(), request.getUri().toString())
.withTag(Tags.PEER_PORT.getKey(), request.getUri().port())
.withTag(Tags.PEER_HOSTNAME.getKey(), request.getUri().host().address());
if (Config.get().isHttpClientSplitByDomain()) {
builder.withTag(DDTags.SERVICE_NAME, request.getUri().host().address());
}
}
final Scope scope = builder.startActive(false);
if (request != null) { if (request != null) {
final AkkaHttpHeaders headers = new AkkaHttpHeaders(request); final AkkaHttpHeaders headers = new AkkaHttpHeaders(request);
@ -147,8 +128,8 @@ public final class AkkaHttpClientInstrumentation extends Instrumenter.Default {
if (throwable == null) { if (throwable == null) {
responseFuture.onComplete(new OnCompleteHandler(span), thiz.system().dispatcher()); responseFuture.onComplete(new OnCompleteHandler(span), thiz.system().dispatcher());
} else { } else {
Tags.ERROR.set(span, Boolean.TRUE); AkkaHttpClientDecorator.INSTANCE.onError(span, throwable);
span.log(Collections.singletonMap(ERROR_OBJECT, throwable)); AkkaHttpClientDecorator.INSTANCE.beforeFinish(span);
span.finish(); span.finish();
} }
scope.close(); scope.close();
@ -193,11 +174,11 @@ public final class AkkaHttpClientInstrumentation extends Instrumenter.Default {
@Override @Override
public Void apply(final Try<HttpResponse> result) { public Void apply(final Try<HttpResponse> result) {
if (result.isSuccess()) { if (result.isSuccess()) {
Tags.HTTP_STATUS.set(span, result.get().status().intValue()); AkkaHttpClientDecorator.INSTANCE.onResponse(span, result.get());
} else { } else {
Tags.ERROR.set(span, true); AkkaHttpClientDecorator.INSTANCE.onError(span, result.failed().get());
span.log(Collections.singletonMap(ERROR_OBJECT, result.failed().get()));
} }
AkkaHttpClientDecorator.INSTANCE.beforeFinish(span);
span.finish(); span.finish();
return null; return null;
} }

View File

@ -1,15 +1,10 @@
package datadog.trace.instrumentation.akkahttp package datadog.trace.instrumentation.akkahttp
import java.util.Collections
import akka.NotUsed import akka.NotUsed
import akka.http.scaladsl.model.{HttpRequest, HttpResponse} import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import akka.stream.scaladsl.Flow import akka.stream.scaladsl.Flow
import datadog.trace.api.{Config, DDSpanTypes, DDTags}
import io.opentracing.Span import io.opentracing.Span
import io.opentracing.log.Fields.ERROR_OBJECT
import io.opentracing.propagation.Format import io.opentracing.propagation.Format
import io.opentracing.tag.Tags
import io.opentracing.util.GlobalTracer import io.opentracing.util.GlobalTracer
import scala.util.{Failure, Success, Try} import scala.util.{Failure, Success, Try}
@ -20,29 +15,18 @@ object AkkaHttpClientTransformFlow {
Flow.fromFunction((input: (HttpRequest, T)) => { Flow.fromFunction((input: (HttpRequest, T)) => {
val (request, data) = input val (request, data) = input
span = GlobalTracer.get span = GlobalTracer.get.buildSpan("akka-http.request").start()
.buildSpan("akka-http.request") AkkaHttpClientDecorator.INSTANCE.afterStart(span)
.withTag(Tags.SPAN_KIND.getKey, Tags.SPAN_KIND_CLIENT) AkkaHttpClientDecorator.INSTANCE.onRequest(span, request)
.withTag(Tags.HTTP_METHOD.getKey, request.method.value)
.withTag(Tags.PEER_HOSTNAME.getKey, request.getUri().host().address())
.withTag(Tags.PEER_PORT.getKey, request.getUri().port())
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT)
.withTag(Tags.COMPONENT.getKey, "akka-http-client")
.withTag(Tags.HTTP_URL.getKey, request.getUri.toString)
.start()
if (Config.get.isHttpClientSplitByDomain) {
span.setTag(DDTags.SERVICE_NAME, request.getUri.host.address)
}
val headers = new AkkaHttpClientInstrumentation.AkkaHttpHeaders(request) val headers = new AkkaHttpClientInstrumentation.AkkaHttpHeaders(request)
GlobalTracer.get.inject(span.context, Format.Builtin.HTTP_HEADERS, headers) GlobalTracer.get.inject(span.context, Format.Builtin.HTTP_HEADERS, headers)
(headers.getRequest, data) (headers.getRequest, data)
}).via(flow).map(output => { }).via(flow).map(output => {
output._1 match { output._1 match {
case Success(response) => Tags.HTTP_STATUS.set(span, response.status.intValue) case Success(response) => AkkaHttpClientDecorator.INSTANCE.onResponse(span, response)
case Failure(e) => case Failure(e) => AkkaHttpClientDecorator.INSTANCE.onError(span, e)
Tags.ERROR.set(span, true)
span.log(Collections.singletonMap(ERROR_OBJECT, e))
} }
AkkaHttpClientDecorator.INSTANCE.beforeFinish(span)
span.finish() span.finish()
output output
}) })

View File

@ -0,0 +1,44 @@
package datadog.trace.instrumentation.akkahttp;
import akka.http.scaladsl.model.HttpRequest;
import akka.http.scaladsl.model.HttpResponse;
import datadog.trace.agent.decorator.HttpServerDecorator;
public class AkkaHttpServerDecorator extends HttpServerDecorator<HttpRequest, HttpResponse> {
public static final AkkaHttpServerDecorator INSTANCE = new AkkaHttpServerDecorator();
@Override
protected String[] instrumentationNames() {
return new String[] {"akka-http", "akka-http-server"};
}
@Override
protected String component() {
return "akka-http-server";
}
@Override
protected String method(final HttpRequest httpRequest) {
return httpRequest.method().value();
}
@Override
protected String url(final HttpRequest httpRequest) {
return httpRequest.uri().toString();
}
@Override
protected String hostname(final HttpRequest httpRequest) {
return httpRequest.getUri().host().address();
}
@Override
protected Integer port(final HttpRequest httpRequest) {
return httpRequest.getUri().port();
}
@Override
protected Integer status(final HttpResponse httpResponse) {
return httpResponse.status().intValue();
}
}

View File

@ -1,6 +1,5 @@
package datadog.trace.instrumentation.akkahttp; package datadog.trace.instrumentation.akkahttp;
import static io.opentracing.log.Fields.ERROR_OBJECT;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
@ -10,8 +9,6 @@ import akka.http.scaladsl.model.HttpResponse;
import akka.stream.Materializer; import akka.stream.Materializer;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags;
import datadog.trace.context.TraceScope; import datadog.trace.context.TraceScope;
import io.opentracing.Scope; import io.opentracing.Scope;
import io.opentracing.Span; import io.opentracing.Span;
@ -20,7 +17,6 @@ import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap; import io.opentracing.propagation.TextMap;
import io.opentracing.tag.Tags; import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer; import io.opentracing.util.GlobalTracer;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
@ -54,7 +50,11 @@ public final class AkkaHttpServerInstrumentation extends Instrumenter.Default {
AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper", AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper",
AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$1", AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$1",
AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$2", AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$2",
AkkaHttpServerInstrumentation.class.getName() + "$AkkaHttpServerHeaders" AkkaHttpServerInstrumentation.class.getName() + "$AkkaHttpServerHeaders",
"datadog.trace.agent.decorator.BaseDecorator",
"datadog.trace.agent.decorator.ServerDecorator",
"datadog.trace.agent.decorator.HttpServerDecorator",
packageName + ".AkkaHttpServerDecorator",
}; };
} }
@ -104,13 +104,11 @@ public final class AkkaHttpServerInstrumentation extends Instrumenter.Default {
GlobalTracer.get() GlobalTracer.get()
.buildSpan("akka-http.request") .buildSpan("akka-http.request")
.asChildOf(extractedContext) .asChildOf(extractedContext)
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
.withTag(Tags.HTTP_METHOD.getKey(), request.method().value())
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_SERVER)
.withTag(Tags.COMPONENT.getKey(), "akka-http-server")
.withTag(Tags.HTTP_URL.getKey(), request.getUri().toString())
.startActive(false); .startActive(false);
AkkaHttpServerDecorator.INSTANCE.afterStart(scope.span());
AkkaHttpServerDecorator.INSTANCE.onRequest(scope.span(), request);
if (scope instanceof TraceScope) { if (scope instanceof TraceScope) {
((TraceScope) scope).setAsyncPropagation(true); ((TraceScope) scope).setAsyncPropagation(true);
} }
@ -118,7 +116,8 @@ public final class AkkaHttpServerInstrumentation extends Instrumenter.Default {
} }
public static void finishSpan(final Span span, final HttpResponse response) { public static void finishSpan(final Span span, final HttpResponse response) {
Tags.HTTP_STATUS.set(span, response.status().intValue()); AkkaHttpServerDecorator.INSTANCE.onResponse(span, response);
AkkaHttpServerDecorator.INSTANCE.beforeFinish(span);
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) { if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(false); ((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(false);
@ -127,9 +126,9 @@ public final class AkkaHttpServerInstrumentation extends Instrumenter.Default {
} }
public static void finishSpan(final Span span, final Throwable t) { public static void finishSpan(final Span span, final Throwable t) {
Tags.ERROR.set(span, true); AkkaHttpServerDecorator.INSTANCE.onError(span, t);
span.log(Collections.singletonMap(ERROR_OBJECT, t));
Tags.HTTP_STATUS.set(span, 500); Tags.HTTP_STATUS.set(span, 500);
AkkaHttpServerDecorator.INSTANCE.beforeFinish(span);
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) { if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(false); ((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(false);

View File

@ -56,6 +56,8 @@ class AkkaHttpServerInstrumentationTest extends AgentTestRunner {
"$Tags.HTTP_STATUS.key" 200 "$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "http://localhost:$port/test" "$Tags.HTTP_URL.key" "http://localhost:$port/test"
"$Tags.HTTP_METHOD.key" "GET" "$Tags.HTTP_METHOD.key" "GET"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" port
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER "$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.COMPONENT.key" "akka-http-server" "$Tags.COMPONENT.key" "akka-http-server"
@ -98,6 +100,8 @@ class AkkaHttpServerInstrumentationTest extends AgentTestRunner {
"$Tags.HTTP_STATUS.key" 500 "$Tags.HTTP_STATUS.key" 500
"$Tags.HTTP_URL.key" "http://localhost:$port/$endpoint" "$Tags.HTTP_URL.key" "http://localhost:$port/$endpoint"
"$Tags.HTTP_METHOD.key" "GET" "$Tags.HTTP_METHOD.key" "GET"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" port
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER "$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.COMPONENT.key" "akka-http-server" "$Tags.COMPONENT.key" "akka-http-server"
@ -138,6 +142,8 @@ class AkkaHttpServerInstrumentationTest extends AgentTestRunner {
"$Tags.HTTP_STATUS.key" 500 "$Tags.HTTP_STATUS.key" 500
"$Tags.HTTP_URL.key" "http://localhost:$port/server-error" "$Tags.HTTP_URL.key" "http://localhost:$port/server-error"
"$Tags.HTTP_METHOD.key" "GET" "$Tags.HTTP_METHOD.key" "GET"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" port
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER "$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.COMPONENT.key" "akka-http-server" "$Tags.COMPONENT.key" "akka-http-server"
@ -177,6 +183,8 @@ class AkkaHttpServerInstrumentationTest extends AgentTestRunner {
"$Tags.HTTP_STATUS.key" 404 "$Tags.HTTP_STATUS.key" 404
"$Tags.HTTP_URL.key" "http://localhost:$port/not-found" "$Tags.HTTP_URL.key" "http://localhost:$port/not-found"
"$Tags.HTTP_METHOD.key" "GET" "$Tags.HTTP_METHOD.key" "GET"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" port
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER "$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER "$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.COMPONENT.key" "akka-http-server" "$Tags.COMPONENT.key" "akka-http-server"

View File

@ -0,0 +1,60 @@
package datadog.trace.instrumentation.apachehttpclient;
import datadog.trace.agent.decorator.HttpClientDecorator;
import java.net.URI;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
public class ApacheHttpClientDecorator extends HttpClientDecorator<HttpUriRequest, HttpResponse> {
public static final ApacheHttpClientDecorator INSTANCE = new ApacheHttpClientDecorator();
@Override
protected String[] instrumentationNames() {
return new String[] {"httpclient", "apache-httpclient", "apache-http-client"};
}
@Override
protected String component() {
return "apache-httpclient";
}
@Override
protected String service() {
return null;
}
@Override
protected String method(final HttpUriRequest httpRequest) {
return httpRequest.getRequestLine().getMethod();
}
@Override
protected String url(final HttpUriRequest httpRequest) {
return httpRequest.getRequestLine().getUri();
}
@Override
protected String hostname(final HttpUriRequest httpRequest) {
final URI uri = httpRequest.getURI();
if (uri != null) {
return uri.getHost();
} else {
return null;
}
}
@Override
protected Integer port(final HttpUriRequest httpRequest) {
final URI uri = httpRequest.getURI();
if (uri != null) {
return uri.getPort();
} else {
return null;
}
}
@Override
protected Integer status(final HttpResponse httpResponse) {
return httpResponse.getStatusLine().getStatusCode();
}
}

View File

@ -1,7 +1,6 @@
package datadog.trace.instrumentation.apachehttpclient; package datadog.trace.instrumentation.apachehttpclient;
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
import static io.opentracing.log.Fields.ERROR_OBJECT;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract; import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isMethod;
@ -11,19 +10,14 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.Config;
import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags;
import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.bootstrap.CallDepthThreadLocalMap;
import io.opentracing.Scope; import io.opentracing.Scope;
import io.opentracing.Span; import io.opentracing.Span;
import io.opentracing.Tracer; import io.opentracing.Tracer;
import io.opentracing.propagation.Format; import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap; import io.opentracing.propagation.TextMap;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer; import io.opentracing.util.GlobalTracer;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
@ -42,7 +36,7 @@ import org.apache.http.client.methods.HttpUriRequest;
public class ApacheHttpClientInstrumentation extends Instrumenter.Default { public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
public ApacheHttpClientInstrumentation() { public ApacheHttpClientInstrumentation() {
super("httpclient"); super("httpclient", "apache-httpclient", "apache-http-client");
} }
@Override @Override
@ -55,6 +49,10 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
return new String[] { return new String[] {
getClass().getName() + "$HttpHeadersInjectAdapter", getClass().getName() + "$HttpHeadersInjectAdapter",
getClass().getName() + "$WrappingStatusSettingResponseHandler", getClass().getName() + "$WrappingStatusSettingResponseHandler",
"datadog.trace.agent.decorator.BaseDecorator",
"datadog.trace.agent.decorator.ClientDecorator",
"datadog.trace.agent.decorator.HttpClientDecorator",
packageName + ".ApacheHttpClientDecorator",
}; };
} }
@ -91,18 +89,12 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
return null; return null;
} }
final Tracer tracer = GlobalTracer.get(); final Tracer tracer = GlobalTracer.get();
final Scope scope = final Scope scope = tracer.buildSpan("http.request").startActive(true);
tracer
.buildSpan("http.request")
.withTag(Tags.COMPONENT.getKey(), "apache-httpclient")
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT)
.withTag(Tags.HTTP_METHOD.getKey(), request.getRequestLine().getMethod())
.withTag(Tags.HTTP_URL.getKey(), request.getRequestLine().getUri())
.startActive(true);
final Span span = scope.span(); final Span span = scope.span();
ApacheHttpClientDecorator.INSTANCE.afterStart(span);
ApacheHttpClientDecorator.INSTANCE.onRequest(span, request);
// Wrap the handler so we capture the status code // Wrap the handler so we capture the status code
if (handler1 instanceof ResponseHandler) { if (handler1 instanceof ResponseHandler) {
handler1 = new WrappingStatusSettingResponseHandler(span, (ResponseHandler) handler1); handler1 = new WrappingStatusSettingResponseHandler(span, (ResponseHandler) handler1);
@ -116,15 +108,6 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
tracer.inject( tracer.inject(
span.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersInjectAdapter(request)); span.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersInjectAdapter(request));
} }
final URI uri = request.getURI();
// zuul users have encountered cases where getURI returns null
if (null != uri) {
Tags.PEER_PORT.set(span, uri.getPort() == -1 ? 80 : uri.getPort());
Tags.PEER_HOSTNAME.set(span, uri.getHost());
if (Config.get().isHttpClientSplitByDomain()) {
span.setTag(DDTags.SERVICE_NAME, uri.getHost());
}
}
return scope; return scope;
} }
@ -134,22 +117,22 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
@Advice.Return final Object result, @Advice.Return final Object result,
@Advice.Thrown final Throwable throwable) { @Advice.Thrown final Throwable throwable) {
if (scope != null) { if (scope != null) {
try {
final Span span = scope.span(); final Span span = scope.span();
if (result instanceof HttpResponse) { if (result instanceof HttpResponse) {
Tags.HTTP_STATUS.set(span, ((HttpResponse) result).getStatusLine().getStatusCode()); ApacheHttpClientDecorator.INSTANCE.onResponse(span, (HttpResponse) result);
} // else they probably provided a ResponseHandler. } // else they probably provided a ResponseHandler.
if (throwable != null) { ApacheHttpClientDecorator.INSTANCE.onError(span, throwable);
Tags.ERROR.set(span, Boolean.TRUE); ApacheHttpClientDecorator.INSTANCE.beforeFinish(span);
span.log(singletonMap(ERROR_OBJECT, throwable)); } finally {
span.finish();
}
scope.close(); scope.close();
CallDepthThreadLocalMap.reset(HttpClient.class); CallDepthThreadLocalMap.reset(HttpClient.class);
} }
} }
} }
}
public static class WrappingStatusSettingResponseHandler implements ResponseHandler { public static class WrappingStatusSettingResponseHandler implements ResponseHandler {
final Span span; final Span span;
@ -164,7 +147,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
public Object handleResponse(final HttpResponse response) public Object handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException { throws ClientProtocolException, IOException {
if (null != span) { if (null != span) {
Tags.HTTP_STATUS.set(span, response.getStatusLine().getStatusCode()); ApacheHttpClientDecorator.INSTANCE.onResponse(span, response);
} }
return handler.handleResponse(response); return handler.handleResponse(response);
} }

View File

@ -58,6 +58,8 @@ class Play26Test extends AgentTestRunner {
"http.status_code" 200 "http.status_code" 200
"http.url" "http://localhost:$port/helloplay/spock" "http.url" "http://localhost:$port/helloplay/spock"
"http.method" "GET" "http.method" "GET"
"peer.hostname" "localhost"
"peer.port" port
"span.kind" "server" "span.kind" "server"
"span.type" DDSpanTypes.HTTP_SERVER "span.type" DDSpanTypes.HTTP_SERVER
"component" "akka-http-server" "component" "akka-http-server"
@ -109,6 +111,8 @@ class Play26Test extends AgentTestRunner {
"http.status_code" 500 "http.status_code" 500
"http.url" "http://localhost:$port/make-error" "http.url" "http://localhost:$port/make-error"
"http.method" "GET" "http.method" "GET"
"peer.hostname" "localhost"
"peer.port" port
"span.kind" "server" "span.kind" "server"
"span.type" DDSpanTypes.HTTP_SERVER "span.type" DDSpanTypes.HTTP_SERVER
"component" "akka-http-server" "component" "akka-http-server"
@ -160,6 +164,8 @@ class Play26Test extends AgentTestRunner {
"http.status_code" 500 "http.status_code" 500
"http.url" "http://localhost:$port/exception" "http.url" "http://localhost:$port/exception"
"http.method" "GET" "http.method" "GET"
"peer.hostname" "localhost"
"peer.port" port
"span.kind" "server" "span.kind" "server"
"span.type" DDSpanTypes.HTTP_SERVER "span.type" DDSpanTypes.HTTP_SERVER
"component" "akka-http-server" "component" "akka-http-server"
@ -214,6 +220,8 @@ class Play26Test extends AgentTestRunner {
"http.status_code" 404 "http.status_code" 404
"http.url" "http://localhost:$port/nowhere" "http.url" "http://localhost:$port/nowhere"
"http.method" "GET" "http.method" "GET"
"peer.hostname" "localhost"
"peer.port" port
"span.kind" "server" "span.kind" "server"
"span.type" DDSpanTypes.HTTP_SERVER "span.type" DDSpanTypes.HTTP_SERVER
"component" "akka-http-server" "component" "akka-http-server"