Merge pull request #837 from DataDog/mar-kolya/fix-apache-async-instrumentation-with-null-callback

Handle null callback in HttpAsyncApache instrumentation
This commit is contained in:
Nikolay Martynov 2019-05-16 17:41:39 -04:00 committed by GitHub
commit 94907270a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 6 deletions

View File

@ -180,6 +180,7 @@ public class ApacheHttpAsyncClientInstrumentation extends Instrumenter.Default {
}
this.clientSpan = clientSpan;
this.context = context;
// Note: this can be null in real life, so we have to handle this carefully
this.delegate = delegate;
}
@ -190,11 +191,11 @@ public class ApacheHttpAsyncClientInstrumentation extends Instrumenter.Default {
clientSpan.finish(); // Finish span before calling delegate
if (parentContinuation == null) {
delegate.completed(result);
completeDelegate(result);
} else {
try (final TraceScope scope = parentContinuation.activate()) {
scope.setAsyncPropagation(true);
delegate.completed(result);
completeDelegate(result);
}
}
}
@ -207,11 +208,11 @@ public class ApacheHttpAsyncClientInstrumentation extends Instrumenter.Default {
clientSpan.finish(); // Finish span before calling delegate
if (parentContinuation == null) {
delegate.failed(ex);
failDelegate(ex);
} else {
try (final TraceScope scope = parentContinuation.activate()) {
scope.setAsyncPropagation(true);
delegate.failed(ex);
failDelegate(ex);
}
}
}
@ -223,14 +224,32 @@ public class ApacheHttpAsyncClientInstrumentation extends Instrumenter.Default {
clientSpan.finish(); // Finish span before calling delegate
if (parentContinuation == null) {
delegate.cancelled();
cancelDelegate();
} else {
try (final TraceScope scope = parentContinuation.activate()) {
scope.setAsyncPropagation(true);
delegate.cancelled();
cancelDelegate();
}
}
}
private void completeDelegate(final T result) {
if (delegate != null) {
delegate.completed(result);
}
}
private void failDelegate(final Exception ex) {
if (delegate != null) {
delegate.failed(ex);
}
}
private void cancelDelegate() {
if (delegate != null) {
delegate.cancelled();
}
}
}
public static class HttpHeadersInjectAdapter implements TextMap {

View File

@ -0,0 +1,50 @@
import datadog.trace.agent.test.base.HttpClientTest
import datadog.trace.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientDecorator
import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.nio.client.HttpAsyncClients
import org.apache.http.message.BasicHeader
import spock.lang.AutoCleanup
import spock.lang.Shared
import java.util.concurrent.Future
class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest<ApacheHttpAsyncClientDecorator> {
@AutoCleanup
@Shared
def client = HttpAsyncClients.createDefault()
def setupSpec() {
client.start()
}
@Override
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
assert method == "GET"
HttpGet request = new HttpGet(uri)
headers.entrySet().each {
request.addHeader(new BasicHeader(it.key, it.value))
}
// The point here is to test case when callback is null - fire-and-forget style
// So to make sure request is done we start request, wait for future to finish
// and then call callback if present.
Future future = client.execute(request, null)
future.get()
if (callback != null) {
callback()
}
return 200
}
@Override
ApacheHttpAsyncClientDecorator decorator() {
return ApacheHttpAsyncClientDecorator.DECORATE
}
@Override
Integer statusOnRedirectError() {
return 302
}
}