diff --git a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java index 52ce8855048..9a596ae90a1 100644 --- a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java @@ -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; @@ -20,6 +21,9 @@ public class SpringWebHttpServerDecorator extends HttpServerDecorator { + // 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"); @@ -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)); } if (mv.getView() != null) { span.setTag("view.type", className(mv.getView().getClass())); diff --git a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/test/groovy/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecoratorTest.groovy b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/test/groovy/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecoratorTest.groovy new file mode 100644 index 00000000000..28952694a40 --- /dev/null +++ b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/test/groovy/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecoratorTest.groovy @@ -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 + } +} diff --git a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/main/java17/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecorator.java b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/main/java17/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecorator.java index 79b89c1aad5..162e750fbb4 100644 --- a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/main/java17/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/main/java17/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecorator.java @@ -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; @@ -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"); @@ -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())); diff --git a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/test/groovy/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecoratorTest.groovy b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/test/groovy/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecoratorTest.groovy new file mode 100644 index 00000000000..6979a46dff6 --- /dev/null +++ b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/test/groovy/datadog/trace/instrumentation/springweb6/SpringWebHttpServerDecoratorTest.groovy @@ -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 + } +} diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java index 60e94418f09..05a6ffd7b11 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java @@ -119,6 +119,7 @@ public final class GeneralConfig { public static final String TAG_VALUE_UTF8_CACHE_SIZE = "tag.value.utf8.cache.size"; public static final String SPAN_BUILDER_REUSE_ENABLED = "span.builder.reuse.enabled"; public static final String STACK_TRACE_LENGTH_LIMIT = "stack.trace.length.limit"; + public static final String ERROR_MESSAGE_LENGTH_LIMIT = "error.message.length.limit"; public static final String SSI_INJECTION_ENABLED = "injection.enabled"; public static final String SSI_INJECTION_FORCE = "inject.force"; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java index 6949ddf31de..46112884e31 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java @@ -31,6 +31,7 @@ import datadog.trace.bootstrap.instrumentation.api.ResourceNamePriorities; import datadog.trace.bootstrap.instrumentation.api.SpanWrapper; import datadog.trace.core.util.StackTraces; +import datadog.trace.util.Strings; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Collections; @@ -342,7 +343,9 @@ public boolean isSameTrace(final AgentSpan otherSpan) { @Override public DDSpan setErrorMessage(final String errorMessage) { - return setTag(DDTags.ERROR_MSG, errorMessage); + return setTag( + DDTags.ERROR_MSG, + Strings.truncate(errorMessage, Config.get().getErrorMessageLengthLimit())); } @Override @@ -366,8 +369,8 @@ public DDSpan addThrowable(Throwable error, byte errorPriority) { DDTags.ERROR_STACK, StackTraces.getStackTrace(error, Config.get().getStackTraceLengthLimit())); } - - setTag(DDTags.ERROR_MSG, message); + setTag( + DDTags.ERROR_MSG, Strings.truncate(message, Config.get().getErrorMessageLengthLimit())); setTag(DDTags.ERROR_TYPE, error.getClass().getName()); if (isExceptionReplayEnabled()) { DebuggerContext.handleException(error, this); diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 34de791eee7..b573d50157d 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -368,6 +368,7 @@ import static datadog.trace.api.config.GeneralConfig.DOGSTATSD_PORT; import static datadog.trace.api.config.GeneralConfig.DOGSTATSD_START_DELAY; import static datadog.trace.api.config.GeneralConfig.ENV; +import static datadog.trace.api.config.GeneralConfig.ERROR_MESSAGE_LENGTH_LIMIT; import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED; import static datadog.trace.api.config.GeneralConfig.GLOBAL_TAGS; import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_ENABLED; @@ -1343,6 +1344,7 @@ public static String getHostName() { private final int tagNameUtf8CacheSize; private final int tagValueUtf8CacheSize; private final int stackTraceLengthLimit; + private final int errorMessageLengthLimit; private final boolean sfnInjectDatadogAttributeEnabled; private final boolean sqsInjectDatadogAttributeEnabled; @@ -3087,6 +3089,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) : Integer.MAX_VALUE; // no effective limit (old behavior) this.stackTraceLengthLimit = configProvider.getInteger(STACK_TRACE_LENGTH_LIMIT, defaultStackTraceLengthLimit); + this.errorMessageLengthLimit = + configProvider.getInteger(ERROR_MESSAGE_LENGTH_LIMIT, Integer.MAX_VALUE); this.rumInjectorConfig = parseRumConfig(configProvider); @@ -4910,6 +4914,10 @@ public int getStackTraceLengthLimit() { return stackTraceLengthLimit; } + public int getErrorMessageLengthLimit() { + return errorMessageLengthLimit; + } + public boolean isSqsInjectDatadogAttributeEnabled() { return sqsInjectDatadogAttributeEnabled; } diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index a1569256c66..62ee42ec8a1 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -1385,6 +1385,14 @@ "aliases": [] } ], + "DD_ERROR_MESSAGE_LENGTH_LIMIT": [ + { + "version": "A", + "type": "int", + "default": "2147483647", + "aliases": [] + } + ], "DD_EXCEPTION_DEBUGGING_ENABLED": [ { "version": "A", @@ -10345,6 +10353,14 @@ "aliases": ["DD_TRACE_INTEGRATION_SPRING_WEB_ENABLED", "DD_INTEGRATION_SPRING_WEB_ENABLED"] } ], + "DD_TRACE_SPRING_WEB_VIEW_NAME_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_TRACE_SPRING_WS_2_ENABLED": [ { "version": "A",