Skip to content

Commit 97bc072

Browse files
authored
Merge pull request #2197 from DataDog/tyler/404-spring
Avoid grouping Spring Web routed requests into 404 bucket
2 parents 13d2ccd + bc62d57 commit 97bc072

File tree

5 files changed

+41
-15
lines changed

5 files changed

+41
-15
lines changed

dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/HandlerAdapterInstrumentation.java

+3-11
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
2323
import java.util.Map;
2424
import javax.servlet.http.HttpServletRequest;
25-
import javax.servlet.http.HttpServletResponse;
2625
import net.bytebuddy.asm.Advice;
2726
import net.bytebuddy.description.method.MethodDescription;
2827
import net.bytebuddy.description.type.TypeDescription;
@@ -71,10 +70,9 @@ public static class ControllerAdvice {
7170
@Advice.OnMethodEnter(suppress = Throwable.class)
7271
public static AgentScope nameResourceAndStartSpan(
7372
@Advice.Argument(0) final HttpServletRequest request,
74-
@Advice.Argument(2) final Object handler,
75-
@Advice.Local("_parentSpan") Object parentSpan) {
73+
@Advice.Argument(2) final Object handler) {
7674
// Name the parent span based on the matching pattern
77-
parentSpan = request.getAttribute(DD_SPAN_ATTRIBUTE);
75+
Object parentSpan = request.getAttribute(DD_SPAN_ATTRIBUTE);
7876
if (parentSpan instanceof AgentSpan) {
7977
DECORATE.onRequest((AgentSpan) parentSpan, request);
8078
}
@@ -97,16 +95,10 @@ public static AgentScope nameResourceAndStartSpan(
9795

9896
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
9997
public static void stopSpan(
100-
@Advice.Argument(1) HttpServletResponse response,
101-
@Advice.Local("_parentSpan") Object parentSpan,
102-
@Advice.Enter final AgentScope scope,
103-
@Advice.Thrown final Throwable throwable) {
98+
@Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable throwable) {
10499
if (scope == null) {
105100
return;
106101
}
107-
if (parentSpan instanceof AgentSpan) {
108-
DECORATE.onResponse((AgentSpan) parentSpan, response);
109-
}
110102

111103
DECORATE.onError(scope, throwable);
112104
DECORATE.beforeFinish(scope);

dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ public AgentSpan onRequest(final AgentSpan span, final HttpServletRequest reques
9696
final String method = request.getMethod();
9797
final Object bestMatchingPattern =
9898
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
99-
if (method != null && bestMatchingPattern != null) {
99+
if (method != null && bestMatchingPattern != null && !bestMatchingPattern.equals("/**")) {
100+
// universal matching is not helpful (and prevents 404 renaming in URLAsResourceNameRule).
100101
final CharSequence resourceName =
101102
RESOURCE_NAME_CACHE.computeIfAbsent(
102103
Pair.of(method, bestMatchingPattern), RESOURCE_NAME_JOINER);

dd-java-agent/instrumentation/spring-webmvc-3.1/src/test/groovy/test/boot/SpringBootBasedTest.groovy

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package test.boot
22

3-
43
import datadog.trace.agent.test.asserts.TraceAssert
54
import datadog.trace.agent.test.base.HttpServerTest
65
import datadog.trace.api.DDSpanTypes
@@ -17,6 +16,7 @@ import org.springframework.web.servlet.view.RedirectView
1716
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
1817
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.LOGIN
1918
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND
19+
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_HERE
2020
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT
2121
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS
2222
import static java.util.Collections.singletonMap
@@ -94,6 +94,29 @@ class SpringBootBasedTest extends HttpServerTest<ConfigurableApplicationContext>
9494
testPassword << ["password", "dfsdföääöüüä", "🤓"]
9595
}
9696

97+
def "test not-here"() {
98+
setup:
99+
def request = request(NOT_HERE, method, body).build()
100+
def response = client.newCall(request).execute()
101+
102+
expect:
103+
response.code() == NOT_HERE.status
104+
105+
and:
106+
cleanAndAssertTraces(1) {
107+
trace(3) {
108+
sortSpansByStart()
109+
serverSpan(it, null, null, method, NOT_HERE)
110+
handlerSpan(it, NOT_HERE)
111+
controllerSpan(it)
112+
}
113+
}
114+
115+
where:
116+
method = "GET"
117+
body = null
118+
}
119+
97120
boolean hasResponseSpan(ServerEndpoint endpoint) {
98121
return endpoint == REDIRECT || endpoint == NOT_FOUND || endpoint == LOGIN
99122
}

dd-java-agent/instrumentation/spring-webmvc-3.1/src/test/groovy/test/boot/TestController.groovy

+8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.springframework.web.servlet.view.RedirectView
1313

1414
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
1515
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
16+
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_HERE
1617
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.PATH_PARAM
1718
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_PARAM
1819
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT
@@ -53,6 +54,13 @@ class TestController {
5354
}
5455
}
5556

57+
@RequestMapping("/not-here")
58+
ResponseEntity not_here() {
59+
HttpServerTest.controller(NOT_HERE) {
60+
new ResponseEntity(NOT_HERE.body, HttpStatus.valueOf(NOT_HERE.status))
61+
}
62+
}
63+
5664
@RequestMapping("/error-status")
5765
ResponseEntity error() {
5866
HttpServerTest.controller(ERROR) {

dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import org.slf4j.Logger
1818
import org.slf4j.LoggerFactory
1919
import spock.lang.Shared
2020
import spock.lang.Unroll
21+
2122
import java.util.concurrent.atomic.AtomicBoolean
2223

2324
import static datadog.trace.agent.test.asserts.TraceAssert.assertTrace
@@ -115,7 +116,8 @@ abstract class HttpServerTest<SERVER> extends WithHttpServer<SERVER> {
115116
REDIRECT("redirect", 302, "/redirected"),
116117
ERROR("error-status", 500, "controller error"), // "error" is a special path for some frameworks
117118
EXCEPTION("exception", 500, "controller exception"),
118-
NOT_FOUND("notFound", 404, "not found"),
119+
NOT_FOUND("not-found", 404, "not found"),
120+
NOT_HERE("not-here", 404, "not here"), // Explicitly returned 404 from a valid controller
119121

120122
TIMEOUT("timeout", -1, null),
121123
TIMEOUT_ERROR("timeout_error", -1, null),
@@ -162,7 +164,7 @@ abstract class HttpServerTest<SERVER> extends WithHttpServer<SERVER> {
162164
}
163165

164166
String resource(String method, URI address, String pathParam) {
165-
return status == 404 ? "404" : "$method ${hasPathParam ? pathParam : resolve(address).path}"
167+
return path == "not-found" ? "404" : "$method ${hasPathParam ? pathParam : resolve(address).path}"
166168
}
167169

168170
private static final Map<String, ServerEndpoint> PATH_MAP = values().collectEntries { [it.path, it] }

0 commit comments

Comments
 (0)