Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import datadog.trace.bootstrap.instrumentation.api.URIDataAdapter;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator;
import datadog.trace.util.Strings;
import java.lang.reflect.Method;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -20,6 +21,9 @@

public class SpringWebHttpServerDecorator
extends HttpServerDecorator<HttpServletRequest, HttpServletRequest, HttpServletResponse, Void> {
// source for limits: https://docs.datadoghq.com/tracing/troubleshooting
static final int VIEW_NAME_RESOURCE_LIMIT = 5_000;
static final int VIEW_NAME_TAG_LIMIT = 25_000;

private static final CharSequence SPRING_HANDLER = UTF8BytesString.create("spring.handler");
public static final CharSequence RESPONSE_RENDER = UTF8BytesString.create("response.render");
Expand Down Expand Up @@ -142,8 +146,8 @@ private String getMethodName(final Object handler) {
public AgentSpan onRender(final AgentSpan span, final ModelAndView mv) {
final String viewName = mv.getViewName();
if (viewName != null) {
span.setTag("view.name", viewName);
span.setResourceName(viewName);
span.setTag("view.name", Strings.truncate(viewName, VIEW_NAME_TAG_LIMIT));
span.setResourceName(Strings.truncate(viewName, VIEW_NAME_RESOURCE_LIMIT));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this realistically happen in practice (e.g., do we have a support case)? This is a breaking change and the PR should be labeled accordingly. Moreover, the same reasoning applies to all tags and the resource name, so it would be better to address this holistically rather than focusing on the view name, which seems unlikely to be affected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes sorry I didn't link it, but in https://datadoghq.atlassian.net/browse/APMS-18977 the customer has view names that reach 4 million characters.
It's due to a bad loop in their code, but the idea is that we shouldn't crash even bad code if it doesn't crash by itself.

And we discussed in the TEE sync the idea of truncating at the setTag level, but @dougqh said that there is some cases where we want the truncation to happen later, for instance if an SQL request gets truncated it might prevent the agent from properly parsing it, and then applying the relevant obfuscation algo.

Copy link
Copy Markdown
Contributor

@amarziali amarziali Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn’t have implemented this kind of fix, and I don’t think it’s the right approach. The error looks like a cyclic dispatch, and the logs seem to support this, as spans appear to be closed multiple times and the resource name growing similarly. I would instead focus on ensuring that, if possible, in the case of cyclic calls, we do not repeatedly open spans or set the resource name multiple times. While this is a hypothesis I haven’t fully verified.
wrt resource names, we’ve encountered similar issues before (e.g., with Redis and Mongo resource names). This could be an opportunity to enforce such safeguards globally, potentially behind a feature flag, or to introduce a shared utility to handle it consistently.

}
if (mv.getView() != null) {
span.setTag("view.type", className(mv.getView().getClass()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package datadog.trace.instrumentation.springweb

import datadog.trace.agent.test.InstrumentationSpecification
import org.springframework.web.servlet.ModelAndView

class SpringWebHttpServerDecoratorTest extends InstrumentationSpecification {

def "onRender truncates long view name for tag and resource"() {
given:
def viewName = "a" * (SpringWebHttpServerDecorator.VIEW_NAME_TAG_LIMIT + 12)
def modelAndView = Stub(ModelAndView) {
getViewName() >> viewName
getView() >> null
}
def span = TEST_TRACER.buildSpan("testInstrumentation", "my operation").start()

when:
SpringWebHttpServerDecorator.DECORATE_RENDER.onRender(span, modelAndView)
span.finish()

then:
span.getTag("view.name").toString().length() == SpringWebHttpServerDecorator.VIEW_NAME_TAG_LIMIT
span.getResourceName().length() == SpringWebHttpServerDecorator.VIEW_NAME_RESOURCE_LIMIT
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import static datadog.trace.bootstrap.instrumentation.decorator.http.HttpResourceDecorator.HTTP_RESOURCE_DECORATOR;

import datadog.context.Context;
import datadog.trace.bootstrap.config.provider.ConfigProvider;
import datadog.trace.bootstrap.instrumentation.api.AgentPropagation;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.URIDataAdapter;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator;
import datadog.trace.util.Strings;
import jakarta.servlet.Servlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand All @@ -23,6 +25,11 @@ public class SpringWebHttpServerDecorator

private static final String DD_FILTERED_SPRING_ROUTE_ALREADY_APPLIED =
"datadog.filter.spring.route.applied";
// source for limits: https://docs.datadoghq.com/tracing/troubleshooting
static final int VIEW_NAME_RESOURCE_LIMIT = 5_000;
static final int VIEW_NAME_TAG_LIMIT = 25_000;
private static final boolean VIEW_NAME_ENABLED =
ConfigProvider.getInstance().getBoolean("trace.spring-web.view-name.enabled", true);

private static final CharSequence SPRING_HANDLER = UTF8BytesString.create("spring.handler");
public static final CharSequence RESPONSE_RENDER = UTF8BytesString.create("response.render");
Expand Down Expand Up @@ -147,10 +154,12 @@ private String getMethodName(final Object handler) {
}

public AgentSpan onRender(final AgentSpan span, final ModelAndView mv) {
final String viewName = mv.getViewName();
if (viewName != null) {
span.setTag("view.name", viewName);
span.setResourceName(viewName);
if (VIEW_NAME_ENABLED) {
final String viewName = mv.getViewName();
if (viewName != null) {
span.setTag("view.name", Strings.truncate(viewName, VIEW_NAME_TAG_LIMIT));
span.setResourceName(Strings.truncate(viewName, VIEW_NAME_RESOURCE_LIMIT));
}
}
if (mv.getView() != null) {
span.setTag("view.type", className(mv.getView().getClass()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package datadog.trace.instrumentation.springweb6

import datadog.trace.agent.test.InstrumentationSpecification
import org.springframework.web.servlet.ModelAndView

class SpringWebHttpServerDecoratorTest extends InstrumentationSpecification {

def "onRender truncates long view name for tag and resource"() {
given:
def viewName = "a" * (SpringWebHttpServerDecorator.VIEW_NAME_TAG_LIMIT + 12)
def modelAndView = Stub(ModelAndView) {
getViewName() >> viewName
getView() >> null
}
def span = TEST_TRACER.buildSpan("testInstrumentation", "my operation").start()

when:
SpringWebHttpServerDecorator.DECORATE_RENDER.onRender(span, modelAndView)
span.finish()

then:
span.getTag("view.name").toString().length() == SpringWebHttpServerDecorator.VIEW_NAME_TAG_LIMIT
span.getResourceName().length() == SpringWebHttpServerDecorator.VIEW_NAME_RESOURCE_LIMIT
}
}
Loading