Akka-http-client: handle `singleRquest` throwing an exception
This commit is contained in:
parent
642b862c13
commit
dcbf8d674a
|
@ -15,6 +15,7 @@ import datadog.trace.api.DDSpanTypes;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
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.tag.Tags;
|
||||||
|
@ -79,31 +80,45 @@ public final class AkkaHttpClientInstrumentation extends Instrumenter.Default {
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static Scope methodEnter(
|
public static Scope methodEnter(
|
||||||
@Advice.Argument(value = 0, readOnly = false) HttpRequest request) {
|
@Advice.Argument(value = 0, readOnly = false) HttpRequest request) {
|
||||||
Scope scope =
|
Tracer.SpanBuilder builder =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("akka-http.request")
|
.buildSpan("akka-http.request")
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
|
||||||
.withTag(Tags.HTTP_METHOD.getKey(), request.method().value())
|
|
||||||
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT)
|
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT)
|
||||||
.withTag(Tags.COMPONENT.getKey(), "akka-http-client")
|
.withTag(Tags.COMPONENT.getKey(), "akka-http-client");
|
||||||
.withTag(Tags.HTTP_URL.getKey(), request.getUri().toString())
|
if (request != null) {
|
||||||
.startActive(false);
|
builder =
|
||||||
|
builder
|
||||||
|
.withTag(Tags.HTTP_METHOD.getKey(), request.method().value())
|
||||||
|
.withTag(Tags.HTTP_URL.getKey(), request.getUri().toString());
|
||||||
|
}
|
||||||
|
Scope scope = builder.startActive(false);
|
||||||
|
|
||||||
|
if (request != null) {
|
||||||
AkkaHttpHeaders headers = new AkkaHttpHeaders(request);
|
AkkaHttpHeaders headers = new AkkaHttpHeaders(request);
|
||||||
GlobalTracer.get().inject(scope.span().context(), Format.Builtin.HTTP_HEADERS, headers);
|
GlobalTracer.get().inject(scope.span().context(), Format.Builtin.HTTP_HEADERS, headers);
|
||||||
// Request is immutable, so we have to assign new value once we update headers
|
// Request is immutable, so we have to assign new value once we update headers
|
||||||
request = headers.getRequest();
|
request = headers.getRequest();
|
||||||
|
}
|
||||||
|
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void methodExit(
|
public static void methodExit(
|
||||||
@Advice.Argument(value = 0) final HttpRequest request,
|
@Advice.Argument(value = 0) final HttpRequest request,
|
||||||
@Advice.This final HttpExt thiz,
|
@Advice.This final HttpExt thiz,
|
||||||
@Advice.Return final Future<HttpResponse> responseFuture,
|
@Advice.Return final Future<HttpResponse> responseFuture,
|
||||||
@Advice.Enter final Scope scope) {
|
@Advice.Enter final Scope scope,
|
||||||
responseFuture.onComplete(new OnCompleteHandler(scope.span()), thiz.system().dispatcher());
|
@Advice.Thrown final Throwable throwable) {
|
||||||
|
Span span = scope.span();
|
||||||
|
if (throwable == null) {
|
||||||
|
responseFuture.onComplete(new OnCompleteHandler(span), thiz.system().dispatcher());
|
||||||
|
} else {
|
||||||
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
|
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
|
||||||
|
span.finish();
|
||||||
|
}
|
||||||
scope.close();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,6 +153,36 @@ class AkkaHttpClientInstrumentationTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "singleRequest exception trace" () {
|
||||||
|
when:
|
||||||
|
// Passing null causes NPE in singleRequest
|
||||||
|
Http.get(system).singleRequest(null, materializer)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown NullPointerException
|
||||||
|
assertTraces(TEST_WRITER, 1) {
|
||||||
|
trace(0, 1) {
|
||||||
|
span(0) {
|
||||||
|
parent()
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "akka-http.request"
|
||||||
|
resourceName "akka-http.request"
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
defaultTags()
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
|
"$Tags.COMPONENT.key" "akka-http-client"
|
||||||
|
"$Tags.ERROR.key" true
|
||||||
|
errorTags(NullPointerException)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def "#route pool request trace" () {
|
def "#route pool request trace" () {
|
||||||
setup:
|
setup:
|
||||||
def url = server.address.resolve("/" + route).toURL()
|
def url = server.address.resolve("/" + route).toURL()
|
||||||
|
|
Loading…
Reference in New Issue