Close scope for async servlet requests
MODIFY
dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/FilterChain3Instrumentation.java
dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/FilterChain3Instrumentation.java
@@ -128,6 +128,7 @@ public final class FilterChain3Instrumentation extends Instrumenter.Configurable
final AtomicBoolean activated = new AtomicBoolean(false);
// what if async is already finished? This would not be called
req.getAsyncContext().addListener(new TagSettingAsyncListener(activated, span));
+ scope.close();
} else {
Tags.HTTP_STATUS.set(span, resp.getStatus());
scope.close();

MODIFY
dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/HttpServlet3Instrumentation.java
dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/HttpServlet3Instrumentation.java
@@ -120,6 +120,7 @@ public final class HttpServlet3Instrumentation extends Instrumenter.Configurable
final AtomicBoolean activated = new AtomicBoolean(false);
// what if async is already finished? This would not be called
req.getAsyncContext().addListener(new TagSettingAsyncListener(activated, span));
+ scope.close();
} else {
Tags.HTTP_STATUS.set(span, resp.getStatus());
scope.close();

MODIFY
dd-java-agent/instrumentation/servlet-3/src/test/groovy/JettyServlet3Test.groovy
dd-java-agent/instrumentation/servlet-3/src/test/groovy/JettyServlet3Test.groovy
@@ -122,6 +122,31 @@ class JettyServlet3Test extends AgentTestRunner {
"sync" | "Hello Sync"
}
+ def "servlet instrumentation clears state after async request"() {
+ setup:
+ def request = new Request.Builder()
+ .url("http://localhost:$PORT/async")
+ .get()
+ .build()
+ def numTraces = 5
+ for (int i = 0; i < numTraces; ++i) {
+ client.newCall(request).execute()
+ }
+
+ expect:
+ assertTraces(writer, numTraces) {
+ for (int i = 0; i < numTraces; ++i) {
+ trace(i, 1) {
+ span(0) {
+ serviceName "unnamed-java-app"
+ operationName "servlet.request"
+ resourceName "GET /async"
+ }
+ }
+ }
+ }
+ }
+
def "test #path error servlet call"() {
setup:
def request = new Request.Builder()

MODIFY
dd-trace-ot/src/main/java/datadog/trace/common/writer/ListWriter.java
dd-trace-ot/src/main/java/datadog/trace/common/writer/ListWriter.java
@@ -39,7 +39,8 @@ public class ListWriter extends CopyOnWriteArrayList<List<DDSpan>> implements Wr
latches.add(latch);
}
if (!latch.await(20, TimeUnit.SECONDS)) {
- throw new TimeoutException("Timeout waiting for " + number + " trace(s).");
+ throw new TimeoutException(
+ "Timeout waiting for " + number + " trace(s). ListWriter.size() == " + size());
}
}

Close scope for async servlet requests