From 78fb2a393340ada382ba1b7cd721badd941e64e4 Mon Sep 17 00:00:00 2001 From: Gustavo Lopes Date: Wed, 16 Nov 2022 14:40:40 +0000 Subject: [PATCH] Fix and test liberty-20 --- .../instrumentation/liberty-20/build.gradle | 89 ++++++++++-- .../liberty20/HttpServletExtractAdapter.java | 4 +- .../LibertyServerInstrumentation.java | 13 +- .../ParsePostDataInstrumentation.java | 69 +++++++++ .../ResponseFinishInstrumentation.java | 31 ++-- .../liberty20/Liberty20Test.groovy | 136 ++++++++++++++++++ .../liberty20/PassthruSyncServlet3.java | 103 +++++++++++++ .../src/webapp/resources/WEB-INF/web.xml | 10 ++ .../src/webapp/resources/index.html | 6 + .../servlet/ServletBlockingHelper.java | 73 +++++++++- .../servlet/request-3/build.gradle | 9 ++ .../src/test/groovy/JettyServlet3Test.groovy | 3 +- .../groovy/JettyServletHandlerTest.groovy | 1 + .../src/test/groovy/TomcatServlet3Test.groovy | 3 +- .../servlet3}/TestServlet3.groovy | 31 +++- .../agent/test/base/HttpServerTest.groovy | 24 ++-- ...tOpenLibertySnapshotTest.exception404.snap | 1 + .../datadog/trace/api/gateway/Events.java | 2 +- 18 files changed, 559 insertions(+), 49 deletions(-) create mode 100644 dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ParsePostDataInstrumentation.java create mode 100644 dd-java-agent/instrumentation/liberty-20/src/test/groovy/datadog/trace/instrumentation/liberty20/Liberty20Test.groovy create mode 100644 dd-java-agent/instrumentation/liberty-20/src/webapp/java/datadog/trace/instrumentation/liberty20/PassthruSyncServlet3.java create mode 100644 dd-java-agent/instrumentation/liberty-20/src/webapp/resources/WEB-INF/web.xml create mode 100644 dd-java-agent/instrumentation/liberty-20/src/webapp/resources/index.html rename dd-java-agent/instrumentation/servlet/request-3/src/{test/groovy => testFixtures/groovy/datadog/trace/instrumentation/servlet3}/TestServlet3.groovy (92%) diff --git a/dd-java-agent/instrumentation/liberty-20/build.gradle b/dd-java-agent/instrumentation/liberty-20/build.gradle index 5421a0a6639..61261da7e9c 100644 --- a/dd-java-agent/instrumentation/liberty-20/build.gradle +++ b/dd-java-agent/instrumentation/liberty-20/build.gradle @@ -1,35 +1,108 @@ +plugins { + id 'java-test-fixtures' +} apply from: "$rootDir/gradle/java.gradle" -apply plugin: 'org.unbroken-dome.test-sets' -testSets { - latestDepTest { - dirName = 'test' +String relAppDir = 'openliberty-jars/wlp/usr/servers/defaultServer/dropins/war/testapp' +sourceSets { + webapp { + java { + destinationDirectory.value project.layout.buildDirectory.dir("$relAppDir/WEB-INF/classes") + } + output.resourcesDir = project.layout.buildDirectory.dir("$relAppDir/") } } configurations { zipped + testLogging } +evaluationDependsOn ':dd-java-agent:instrumentation:servlet:request-3' + dependencies { - compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' - implementation project(':dd-java-agent:instrumentation:servlet-common') zipped group: 'io.openliberty', name: 'openliberty-runtime', version: '21.0.0.3', ext: 'zip' + testLogging deps.testLogging + + compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' compileOnly files({ tasks.installOpenLibertyDeps.extractedJars }) + implementation project(':dd-java-agent:instrumentation:servlet-common') + + testImplementation files({ tasks.installOpenLibertyDeps.wsServerJar }) + testRuntimeOnly project(':dd-java-agent:instrumentation:osgi-4.3') + testRuntimeClasspath files({ tasks.filterLogbackClassic.filteredLogbackDir }) + + webappCompileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' + // compileOnly to avoid bringing all the test dependencies to the test app + // these are to be provided by the system classloader on test time + webappCompileOnly project(':dd-java-agent:instrumentation:servlet:request-3') + .tasks['compileTestFixturesJava'].classpath + // only the testFixtures jar (not its dependencies) and groovy should be included in the webapp + webappImplementation files( + project(':dd-java-agent:instrumentation:servlet:request-3') + .getTasksByName('testFixturesJar', false).archiveFile + ) + // use the above instead of: + // webappImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:request-3')) + // because using testFixtures() causes some early evaluation of dependencies + webappRuntimeOnly deps.groovy +} +compileWebappJava.dependsOn ':dd-java-agent:instrumentation:servlet:request-3:testFixturesJar' + +configurations.testRuntimeClasspath { + exclude group: 'ch.qos.logback', module: 'logback-classic' + exclude group: 'org.codehaus.groovy', module: 'groovy-servlet' +} +configurations.webappRuntimeClasspath { + exclude group: 'ch.qos.logback', module: 'logback-classic' } //unzips the dependencies from the 'zipped' configuration so 'compileOnly' can reference it -tasks.register('installOpenLibertyDeps', Sync) { +tasks.register('installOpenLibertyDeps', Copy) { def extractDir = "${buildDir}/openliberty-jars" ext.extractedJars = fileTree(extractDir) { - include "**/*.jar" + include "wlp/lib/*.jar" + builtBy "installOpenLibertyDeps" + } + ext.wsServerJar = fileTree("$extractDir") { + include "wlp/bin/tools/ws-server.jar" builtBy "installOpenLibertyDeps" } dependsOn configurations.zipped + // I didn't manage to get this to work correctly using a Sync task or Sync + outputs.upToDateWhen + // (files are updated when not needed, causing intellij to reindex or they are deemed up to date + // when the extraction was not done at all). + ext.serverXmlFile = file("$extractDir/wlp/usr/servers/defaultServer/server.xml") + onlyIf { + !ext.serverXmlFile.exists() + } from { configurations.zipped.collect { zipTree(it) } } + eachFile { fcd -> + fcd.path = fcd.path.replaceAll(/\/templates\/(servers\/defaultServer\/.+)/, '/usr/$1') + } into extractDir + outputs.file ext.serverXmlFile +} +test.dependsOn webappClasses, installOpenLibertyDeps +test { + jvmArgs += ["-Dserver.xml=${installOpenLibertyDeps.serverXmlFile.absoluteFile}"] } +tasks.register('webappCopyJars', Sync) { + from configurations.webappRuntimeClasspath.findAll { it.name.endsWith('.jar') } + into project.layout.buildDirectory.dir("$relAppDir/WEB-INF/lib") + dependsOn ':dd-java-agent:instrumentation:servlet:request-3:testFixturesJar' +} +test.dependsOn webappCopyJars +tasks.register('filterLogbackClassic', Sync) { + ext.filteredLogbackDir = project.layout.buildDirectory.dir('filteredLogback') + from configurations.testLogging + .findAll { it.name.contains('logback-') } + .collect { zipTree(it) } + exclude 'META-INF/**' + into ext.filteredLogbackDir +} +test.dependsOn filterLogbackClassic diff --git a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/HttpServletExtractAdapter.java b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/HttpServletExtractAdapter.java index dccbd2fc728..6d593d5f886 100644 --- a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/HttpServletExtractAdapter.java +++ b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/HttpServletExtractAdapter.java @@ -40,9 +40,9 @@ public static final class Response extends HttpServletExtractAdapter getHeaderNames(HttpServletResponse request) { + Enumeration getHeaderNames(HttpServletResponse response) { try { - return Collections.enumeration(request.getHeaderNames()); + return Collections.enumeration(response.getHeaderNames()); } catch (NullPointerException e) { // SRTServletResponse#getHeaderNames() will throw NPE if called after response close. return Collections.emptyEnumeration(); diff --git a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java index 0f05003c5f6..df9d2ce3064 100644 --- a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java +++ b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/LibertyServerInstrumentation.java @@ -18,6 +18,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.instrumentation.servlet.ServletBlockingHelper; +import java.util.EnumSet; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import net.bytebuddy.asm.Advice; @@ -32,7 +33,7 @@ public LibertyServerInstrumentation() { @Override public String instrumentedType() { - return "com.ibm.ws.webcontainer.webapp.WebApp"; + return "com.ibm.ws.webcontainer.filter.WebAppFilterManager"; } @Override @@ -51,10 +52,13 @@ public String[] helperClassNames() { public void adviceTransformations(AdviceTransformation transformation) { transformation.applyAdvice( isMethod() - .and(named("handleRequest")) + .and(named("invokeFilters")) .and(takesArgument(0, named("javax.servlet.ServletRequest"))) .and(takesArgument(1, named("javax.servlet.ServletResponse"))) - .and(takesArgument(2, named("com.ibm.wsspi.http.HttpInboundConnection"))), + .and(takesArgument(2, named("com.ibm.wsspi.webcontainer.servlet.IServletContext"))) + .and(takesArgument(3, named("com.ibm.wsspi.webcontainer.RequestProcessor"))) + .and(takesArgument(4, EnumSet.class)) + .and(takesArgument(5, named("com.ibm.wsspi.http.HttpInboundConnection"))), LibertyServerInstrumentation.class.getName() + "$HandleRequestAdvice"); } @@ -110,6 +114,9 @@ public static void closeScope( if (scope != null) { // we cannot get path at the start because the path/context attributes are not yet // initialized + // this has the unfortunate consequence that service name (as set via the tag interceptor) + // of the top span won't match that of its child spans, because it's instead the original + // one that will propagate DECORATE.getPath(scope.span(), request); scope.close(); } diff --git a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ParsePostDataInstrumentation.java b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ParsePostDataInstrumentation.java new file mode 100644 index 00000000000..3374348abfc --- /dev/null +++ b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ParsePostDataInstrumentation.java @@ -0,0 +1,69 @@ +package datadog.trace.instrumentation.liberty20; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static datadog.trace.api.gateway.Events.EVENTS; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isProtected; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.auto.service.AutoService; +import datadog.trace.advice.ActiveRequestContext; +import datadog.trace.advice.RequiresRequestContext; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.api.gateway.CallbackProvider; +import datadog.trace.api.gateway.Flow; +import datadog.trace.api.gateway.RequestContext; +import datadog.trace.api.gateway.RequestContextSlot; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import java.util.Hashtable; +import java.util.function.BiFunction; +import net.bytebuddy.asm.Advice; + +@AutoService(Instrumenter.class) +public class ParsePostDataInstrumentation extends Instrumenter.AppSec + implements Instrumenter.ForKnownTypes { + public ParsePostDataInstrumentation() { + super("liberty"); + } + + @Override + public String[] knownMatchingTypes() { + return new String[] { + "com.ibm.ws.webcontainer.srt.SRTServletRequest", + "com.ibm.ws.webcontainer31.srt.SRTServletRequest31", + }; + } + + @Override + public void adviceTransformations(AdviceTransformation transformation) { + transformation.applyAdvice( + isMethod() + .and(named("parsePostData")) + .and(isPublic().or(isProtected())) + .and(takesArguments(0)) + .and(returns(Hashtable.class)), + ParsePostDataInstrumentation.class.getName() + "$ParsePostDataAdvice"); + } + + @RequiresRequestContext(RequestContextSlot.APPSEC) + static class ParsePostDataAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + static void after( + @Advice.Return Hashtable retval, + @ActiveRequestContext RequestContext reqCtx) { + if (retval == null || retval.isEmpty()) { + return; + } + + CallbackProvider cbp = AgentTracer.get().getCallbackProvider(RequestContextSlot.APPSEC); + BiFunction> callback = + cbp.getCallback(EVENTS.requestBodyProcessed()); + if (callback == null) { + return; + } + callback.apply(reqCtx, retval); + } + } +} diff --git a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ResponseFinishInstrumentation.java b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ResponseFinishInstrumentation.java index 234616e362b..5664efd8ab8 100644 --- a/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ResponseFinishInstrumentation.java +++ b/dd-java-agent/instrumentation/liberty-20/src/main/java/datadog/trace/instrumentation/liberty20/ResponseFinishInstrumentation.java @@ -44,23 +44,34 @@ public void adviceTransformations(AdviceTransformation transformation) { } public static class ResponseFinishAdvice { - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan(@Advice.This SRTServletResponse resp) { + @Advice.OnMethodEnter(suppress = Throwable.class) + static AgentSpan onEnter(@Advice.This SRTServletResponse resp) { + // this is the last opportunity to have any meaningful + // interaction with the response + AgentSpan span = null; IExtendedRequest req = resp.getRequest(); - Object spanObj = null; try { - spanObj = req.getAttribute(DD_SPAN_ATTRIBUTE); + Object spanObj = req.getAttribute(DD_SPAN_ATTRIBUTE); + if (spanObj instanceof AgentSpan) { + span = (AgentSpan) spanObj; + req.setAttribute(DD_SPAN_ATTRIBUTE, null); + DECORATE.onResponse(span, resp); + } } catch (NullPointerException e) { // OpenLiberty will throw NPE on getAttribute if the response has already been closed. } - if (spanObj instanceof AgentSpan) { - req.setAttribute(DD_SPAN_ATTRIBUTE, null); - final AgentSpan span = (AgentSpan) spanObj; - DECORATE.onResponse(span, resp); - DECORATE.beforeFinish(span); - span.finish(); + return span; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.This SRTServletResponse resp, @Advice.Enter AgentSpan span) { + if (span == null) { + return; } + DECORATE.beforeFinish(span); + span.finish(); } } } diff --git a/dd-java-agent/instrumentation/liberty-20/src/test/groovy/datadog/trace/instrumentation/liberty20/Liberty20Test.groovy b/dd-java-agent/instrumentation/liberty-20/src/test/groovy/datadog/trace/instrumentation/liberty20/Liberty20Test.groovy new file mode 100644 index 00000000000..e5167a172ca --- /dev/null +++ b/dd-java-agent/instrumentation/liberty-20/src/test/groovy/datadog/trace/instrumentation/liberty20/Liberty20Test.groovy @@ -0,0 +1,136 @@ +package datadog.trace.instrumentation.liberty20 + +import com.ibm.wsspi.kernel.embeddable.Server +import com.ibm.wsspi.kernel.embeddable.ServerBuilder +import datadog.trace.agent.test.base.HttpServer +import datadog.trace.agent.test.base.HttpServerTest +import datadog.trace.agent.test.utils.PortUtils +import groovy.xml.XmlUtil +import spock.lang.IgnoreIf + +import java.util.concurrent.TimeUnit + +@IgnoreIf({ + // failing because org.apache.xalan.transformer.TransformerImpl is + // instrumented while on the the global ignores list + System.getProperty('java.vm.name') == 'IBM J9 VM' && + System.getProperty('java.specification.version') == '1.8' }) +class Liberty20Test extends HttpServerTest { + + class Liberty20Server implements HttpServer { + File serverXmlFile = new File(System.getProperty('server.xml')) + long serverXmlLastModified + byte[] origServerXml + + def port + Server server + + @Override + void start() { + findRandomPort() + changeServerXml() + ServerBuilder sb = new ServerBuilder(name: 'defaultServer') + server = sb.build() + def result = server.start().get(45, TimeUnit.SECONDS) + if (!result.successful()) { + throw new IllegalStateException("OpenLiberty startup has failed") + } + } + + private void findRandomPort() { + port = PortUtils.randomOpenPort() + } + + private void changeServerXml() { + serverXmlLastModified = serverXmlFile.lastModified() + origServerXml = serverXmlFile.bytes + def xml = new XmlParser().parse(serverXmlFile) + xml.httpEndpoint[0].'@httpPort' = port as String + xml.httpEndpoint[0].attributes().remove 'httpsPort' + + serverXmlFile.text = XmlUtil.serialize(xml) + } + + @Override + void stop() { + def result = server.stop().get(30, TimeUnit.SECONDS) + if (!result.successful()) { + throw new IllegalStateException("OpenLiberty stop has failed") + } + serverXmlFile.bytes = origServerXml + serverXmlFile.lastModified = serverXmlLastModified + } + + @Override + URI address() { + new URI("http://localhost:$port/testapp/") + } + + @Override + String toString() { + return this.class.name + } + } + + @Override + HttpServer server() { + new Liberty20Server() + } + + @Override + String expectedServiceName() { + 'testapp' + } + + @Override + String expectedControllerServiceName() { + super.expectedServiceName() + } + + @Override + Map expectedExtraServerTags(ServerEndpoint endpoint) { + def res = ['servlet.context': '/testapp'] + if (endpoint == ServerEndpoint.NOT_FOUND) { + res['error.msg'] = 'SRVE0190E: File not found: /not-found' + res['error.type'] = 'java.io.FileNotFoundException' + res['error.stack'] = ~/java\.io\.FileNotFoundException: SRVE0190E: File not found: \/not-found.*/ + } else { + res['servlet.path'] = endpoint.path + } + res + } + + @Override + String component() { + 'liberty-server' + } + + @Override + String expectedOperationName() { + "servlet.request" + } + + @Override + boolean testExceptionBody() { + false + } + + @Override + boolean testBodyUrlencoded() { + true + } + + @Override + boolean testBlocking() { + true + } + + @Override + boolean hasExtraErrorInformation() { + true + } + + boolean expectedErrored(ServerEndpoint endpoint) { + endpoint == ServerEndpoint.NOT_FOUND ? true : super.expectedErrored(endpoint) + } +} diff --git a/dd-java-agent/instrumentation/liberty-20/src/webapp/java/datadog/trace/instrumentation/liberty20/PassthruSyncServlet3.java b/dd-java-agent/instrumentation/liberty-20/src/webapp/java/datadog/trace/instrumentation/liberty20/PassthruSyncServlet3.java new file mode 100644 index 00000000000..ead44705e37 --- /dev/null +++ b/dd-java-agent/instrumentation/liberty-20/src/webapp/java/datadog/trace/instrumentation/liberty20/PassthruSyncServlet3.java @@ -0,0 +1,103 @@ +package datadog.trace.instrumentation.liberty20; + +import java.io.IOException; +import java.util.Enumeration; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; + +@WebServlet( + urlPatterns = { + "/success", + "/created", + "/created_input_stream", + "/body-urlencoded", + "/body-json", + "/redirect", + "/forwarded", + "/error-status", + "/exception", + "/custom-exception", + "/not-here", + "/timeout", + "/timeout_error", + "/query", + "/encoded path query", + "/encoded_query", + }) +public class PassthruSyncServlet3 extends HttpServlet { + HttpServlet delegate; + + { + try { + delegate = new datadog.trace.instrumentation.servlet3.TestServlet3.Sync(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void service(ServletRequest req, ServletResponse res) + throws ServletException, IOException { + delegate.service(req, res); + } + + @Override + public void destroy() { + delegate.destroy(); + } + + @Override + public String getInitParameter(String name) { + return delegate.getInitParameter(name); + } + + @Override + public Enumeration getInitParameterNames() { + return delegate.getInitParameterNames(); + } + + @Override + public ServletConfig getServletConfig() { + return delegate.getServletConfig(); + } + + @Override + public ServletContext getServletContext() { + return delegate.getServletContext(); + } + + @Override + public String getServletInfo() { + return delegate.getServletInfo(); + } + + @Override + public void init() throws ServletException { + delegate.init(); + } + + @Override + public void init(ServletConfig config) throws ServletException { + delegate.init(config); + } + + @Override + public String getServletName() { + return delegate.getServletName(); + } + + @Override + public void log(String msg) { + delegate.log(msg); + } + + @Override + public void log(String msg, Throwable t) { + delegate.log(msg, t); + } +} diff --git a/dd-java-agent/instrumentation/liberty-20/src/webapp/resources/WEB-INF/web.xml b/dd-java-agent/instrumentation/liberty-20/src/webapp/resources/WEB-INF/web.xml new file mode 100644 index 00000000000..b4cfedf4f23 --- /dev/null +++ b/dd-java-agent/instrumentation/liberty-20/src/webapp/resources/WEB-INF/web.xml @@ -0,0 +1,10 @@ + + + Test Application + + + index.html + + diff --git a/dd-java-agent/instrumentation/liberty-20/src/webapp/resources/index.html b/dd-java-agent/instrumentation/liberty-20/src/webapp/resources/index.html new file mode 100644 index 00000000000..c4db7b484ca --- /dev/null +++ b/dd-java-agent/instrumentation/liberty-20/src/webapp/resources/index.html @@ -0,0 +1,6 @@ + +Hello World + +

Hello World!

+ + diff --git a/dd-java-agent/instrumentation/servlet-common/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java b/dd-java-agent/instrumentation/servlet-common/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java index 49781ace433..6e8a97403eb 100644 --- a/dd-java-agent/instrumentation/servlet-common/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java +++ b/dd-java-agent/instrumentation/servlet-common/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java @@ -5,13 +5,44 @@ import datadog.trace.bootstrap.blocking.BlockingActionHelper.TemplateType; import java.io.IOException; import java.io.OutputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ServletBlockingHelper { - private static final Logger log = LoggerFactory.getLogger(ServletBlockingHelper.class); + private static final MethodHandle DEBUG_MH; + private static final MethodHandle WARN_MH; + private static final MethodHandle WARN_THR_MH; + + static { + MethodHandle debugMH = null, warnMH = null, warnThrMH = null; + try { + Logger log = LoggerFactory.getLogger(ServletBlockingHelper.class); + debugMH = + MethodHandles.lookup() + .findVirtual(Logger.class, "debug", MethodType.methodType(void.class, String.class)); + debugMH = debugMH.bindTo(log); + warnMH = + MethodHandles.lookup() + .findVirtual(Logger.class, "warn", MethodType.methodType(void.class, String.class)); + warnMH = warnMH.bindTo(log); + warnThrMH = + MethodHandles.lookup() + .findVirtual( + Logger.class, + "warn", + MethodType.methodType(void.class, String.class, Throwable.class)); + warnThrMH = warnThrMH.bindTo(log); + } catch (NoClassDefFoundError | NoSuchMethodException | IllegalAccessException err) { + } + DEBUG_MH = debugMH; + WARN_MH = warnMH; + WARN_THR_MH = warnThrMH; + } public static void commitBlockingResponse( HttpServletRequest httpServletRequest, @@ -35,17 +66,49 @@ public static void commitBlockingResponse( os.write(template); os.close(); } catch (IOException e) { - log.warn("Error sending error page", e); + warn("Error sending error page", e); + } + } + + private static void warn(String msg, Throwable t) { + if (WARN_THR_MH == null) { + return; + } + + try { + WARN_THR_MH.invoke(msg, t); + } catch (Throwable ex) { + } + } + + private static void warn(String msg) { + if (WARN_MH == null) { + return; + } + + try { + WARN_MH.invoke(msg); + } catch (Throwable ex) { + } + } + + private static void debug(String msg) { + if (DEBUG_MH == null) { + return; + } + + try { + DEBUG_MH.invoke(msg); + } catch (Throwable ex) { } } private static boolean start(HttpServletResponse resp, int statusCode) { if (resp.isCommitted()) { - log.warn("response already committed, we can't change it"); - return false; + warn("response already committed, we can't change it"); } - log.debug("Committing blocking response"); + debug("Committing blocking response"); resp.reset(); resp.setStatus(statusCode); diff --git a/dd-java-agent/instrumentation/servlet/request-3/build.gradle b/dd-java-agent/instrumentation/servlet/request-3/build.gradle index 81aed6f472e..d03e20ef2f6 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/build.gradle +++ b/dd-java-agent/instrumentation/servlet/request-3/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'java-test-fixtures' +} + muzzle { pass { name = 'servlet-3.x' @@ -39,6 +43,11 @@ dependencies { compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' implementation project(':dd-java-agent:instrumentation:servlet-common') + testFixturesImplementation(project(':dd-java-agent:testing')) { + exclude group: 'org.eclipse.jetty', module: 'jetty-server' + } + testFixturesCompileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' + testImplementation(project(':dd-java-agent:testing')) { exclude group: 'org.eclipse.jetty', module: 'jetty-server' } diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServlet3Test.groovy b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServlet3Test.groovy index 28a38739e08..efd01bfb8df 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServlet3Test.groovy +++ b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServlet3Test.groovy @@ -2,6 +2,7 @@ import datadog.trace.agent.test.asserts.TraceAssert import datadog.trace.agent.test.base.HttpServer import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.instrumentation.servlet3.AsyncDispatcherDecorator +import datadog.trace.instrumentation.servlet3.TestServlet3 import org.eclipse.jetty.server.Request import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.handler.ErrorHandler @@ -12,7 +13,6 @@ import javax.servlet.ServletException import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse -import static TestServlet3.SERVLET_TIMEOUT import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION @@ -21,6 +21,7 @@ import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRE import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT_ERROR +import static datadog.trace.instrumentation.servlet3.TestServlet3.SERVLET_TIMEOUT abstract class JettyServlet3Test extends AbstractServlet3Test { static final boolean IS_LATEST diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServletHandlerTest.groovy b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServletHandlerTest.groovy index b54b20cf507..1d5e3f05abb 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServletHandlerTest.groovy +++ b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/JettyServletHandlerTest.groovy @@ -1,6 +1,7 @@ import datadog.trace.agent.test.base.HttpServer import datadog.trace.api.config.GeneralConfig import datadog.trace.api.env.CapturedEnvironment +import datadog.trace.instrumentation.servlet3.TestServlet3 import org.eclipse.jetty.server.Request import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.handler.ErrorHandler diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/TomcatServlet3Test.groovy b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/TomcatServlet3Test.groovy index 80664f30e81..024156dcc55 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/TomcatServlet3Test.groovy +++ b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/TomcatServlet3Test.groovy @@ -4,6 +4,7 @@ import datadog.trace.agent.test.base.HttpServer import datadog.trace.api.CorrelationIdentifier import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.instrumentation.servlet3.AsyncDispatcherDecorator +import datadog.trace.instrumentation.servlet3.TestServlet3 import org.apache.catalina.AccessLog import org.apache.catalina.Context import org.apache.catalina.connector.Request @@ -20,13 +21,13 @@ import spock.lang.Unroll import javax.servlet.Servlet import javax.servlet.ServletException -import static TestServlet3.SERVLET_TIMEOUT import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT_ERROR +import static datadog.trace.instrumentation.servlet3.TestServlet3.SERVLET_TIMEOUT @Unroll abstract class TomcatServlet3Test extends AbstractServlet3Test { diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/TestServlet3.groovy b/dd-java-agent/instrumentation/servlet/request-3/src/testFixtures/groovy/datadog/trace/instrumentation/servlet3/TestServlet3.groovy similarity index 92% rename from dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/TestServlet3.groovy rename to dd-java-agent/instrumentation/servlet/request-3/src/testFixtures/groovy/datadog/trace/instrumentation/servlet3/TestServlet3.groovy index d0920efd4d1..84e84869fbb 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/TestServlet3.groovy +++ b/dd-java-agent/instrumentation/servlet/request-3/src/testFixtures/groovy/datadog/trace/instrumentation/servlet3/TestServlet3.groovy @@ -1,3 +1,5 @@ +package datadog.trace.instrumentation.servlet3 + import datadog.trace.agent.test.base.HttpServerTest import groovy.servlet.AbstractHttpServlet @@ -10,6 +12,9 @@ import java.lang.reflect.Field import java.lang.reflect.Modifier import java.util.concurrent.Phaser +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_URLENCODED +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED_IS import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION @@ -19,8 +24,6 @@ import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_ import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_PARAM import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED_IS import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT_ERROR @@ -29,10 +32,15 @@ class TestServlet3 { public static final long SERVLET_TIMEOUT = 1000 static HttpServerTest.ServerEndpoint getEndpoint(HttpServletRequest req) { - // Most correct would be to get the dispatched path from the request - // This is not part of the spec varies by implementation so the simplest is just removing - // "/dispatch" - String truePath = req.servletPath.replace("/dispatch", "") + String truePath + if (req.servletPath == "") { + truePath = req.requestURI - ~'^/[^/]+' + } else { + // Most correct would be to get the dispatched path from the request + // This is not part of the spec varies by implementation so the simplest is just removing + // "/dispatch" + truePath = req.servletPath.replace("/dispatch", "") + } return HttpServerTest.ServerEndpoint.forPath(truePath) } @@ -78,6 +86,15 @@ class TestServlet3 { resp.status = endpoint.status resp.writer.print(endpoint.bodyForQuery(req.queryString)) break + case BODY_URLENCODED: + resp.status = endpoint.status + resp.writer.print( + req.parameterMap + .findAll{ + it.key != 'ignore' + } + .collectEntries {[it.key, it.value as List]} as String) + break case REDIRECT: resp.sendRedirect(endpoint.body) break @@ -254,7 +271,7 @@ class TestServlet3 { static class DispatchRecursive extends AbstractHttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) { - if (req.servletPath.equals("/recursive")) { + if (req.servletPath == "/recursive") { resp.writer.print("Hello Recursive") return } diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy index 2c38d9adebd..42d9f376bb8 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy @@ -115,6 +115,12 @@ abstract class HttpServerTest extends WithHttpServer { CapturedEnvironment.get().getProperties().get(GeneralConfig.SERVICE_NAME) } + // here to go around a limitation in openliberty, where the service name + // is set only at the end of the span and doesn't propagate down + String expectedControllerServiceName() { + expectedServiceName() + } + abstract String expectedOperationName() String expectedResourceName(ServerEndpoint endpoint, String method, URI address) { @@ -771,12 +777,13 @@ abstract class HttpServerTest extends WithHttpServer { def "test error"() { setup: - def request = request(ERROR, method, body).build() + String method = 'GET' + def request = request(ERROR, method, null).build() def response = client.newCall(request).execute() expect: if (bubblesResponse()) { - assert response.body().string() == ERROR.body + assert response.body().string().contains(ERROR.body) assert response.code() == ERROR.status } @@ -794,10 +801,6 @@ abstract class HttpServerTest extends WithHttpServer { } } } - - where: - method = "GET" - body = null } def "test exception"() { @@ -835,6 +838,10 @@ abstract class HttpServerTest extends WithHttpServer { def "test notFound"() { setup: assumeTrue(testNotFound()) + + String method = "GET" + RequestBody body = null + def request = request(NOT_FOUND, method, body).build() def response = client.newCall(request).execute() @@ -855,10 +862,6 @@ abstract class HttpServerTest extends WithHttpServer { } } } - - where: - method = "GET" - body = null } def "test timeout"() { @@ -1131,7 +1134,6 @@ abstract class HttpServerTest extends WithHttpServer { def exception = endpoint == CUSTOM_EXCEPTION ? expectedCustomExceptionType() : expectedExceptionType() def errorMessage = endpoint?.body trace.span { - serviceName expectedServiceName() operationName "controller" resourceName "controller" errored errorMessage != null diff --git a/dd-smoke-tests/springboot-openliberty/snapshots/datadog.smoketest.SpringBootOpenLibertySnapshotTest.exception404.snap b/dd-smoke-tests/springboot-openliberty/snapshots/datadog.smoketest.SpringBootOpenLibertySnapshotTest.exception404.snap index 93e833dc9dd..8f01ad0fe40 100644 --- a/dd-smoke-tests/springboot-openliberty/snapshots/datadog.smoketest.SpringBootOpenLibertySnapshotTest.exception404.snap +++ b/dd-smoke-tests/springboot-openliberty/snapshots/datadog.smoketest.SpringBootOpenLibertySnapshotTest.exception404.snap @@ -83,6 +83,7 @@ "error.msg" "No converter for [class java.util.LinkedHashMap] with preset Content-Type 'text/html;charset=UTF-8'" "error.stack" "org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.LinkedHashMap] with preset Content-Type 'text/html;charset=UTF-8'\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:309)\n\tat org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:219)\n\tat org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:123)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:686)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:791)\n\tat com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1257)\n\tat com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:745)\n\tat com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:442)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:182)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:78)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:1001)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1139)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1010)\n\tat com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.dispatch(WebAppRequestDispatcher.java:1410)\n\tat com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.forward(WebAppRequestDispatcher.java:171)\n\tat com.ibm.ws.webcontainer.webapp.WebApp.sendError(WebApp.java:4350)\n\tat com.ibm.ws.webcontainer.webapp.WebAppDispatcherContext.sendError(WebAppDispatcherContext.java:647)\n\tat com.ibm.ws.webcontainer.webapp.WebAppDispatcherContext.sendError(WebAppDispatcherContext.java:657)\n\tat com.ibm.ws.webcontainer.srt.SRTServletResponse.sendError(SRTServletResponse.java:1334)\n\tat com.ibm.ws.webcontainer.srt.SRTServletResponse.sendError(SRTServletResponse.java:1310)\n\tat org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:488)\n\tat org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:53)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:686)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:791)\n\tat com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1257)\n\tat com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:745)\n\tat com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:442)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:182)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:93)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)\n\tat datadog.trace.instrumentation.springweb.HandlerMappingResourceNameFilter.doFilterInternal(HandlerMappingResourceNameFilter.java:49)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)\n\tat org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:90)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:1001)\n\tat com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1139)\n\tat com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:5057)\n\tat com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.handleRequest(DynamicVirtualHost.java:314)\n\tat com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1006)\n\tat com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:279)\n\tat com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:1146)\n\tat com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.wrapHandlerAndExecute(HttpDispatcherLink.java:427)\n\tat com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.ready(HttpDispatcherLink.java:386)\n\tat com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:566)\n\tat com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleNewRequest(HttpInboundLink.java:500)\n\tat com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.processRequest(HttpInboundLink.java:360)\n\tat com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.ready(HttpInboundLink.java:327)\n\tat com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:167)\n\tat com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:75)\n\tat com.ibm.ws.tcpchannel.internal.WorkQueueManager.requestComplete(WorkQueueManager.java:504)\n\tat com.ibm.ws.tcpchannel.internal.WorkQueueManager.attemptIO(WorkQueueManager.java:574)\n\tat com.ibm.ws.tcpchannel.internal.WorkQueueManager.workerRun(WorkQueueManager.java:958)\n\tat com.ibm.ws.tcpchannel.internal.WorkQueueManager$Worker.run(WorkQueueManager.java:1047)\n\tat com.ibm.ws.threading.internal.ExecutorServiceImpl$RunnableWrapper.run(ExecutorServiceImpl.java:238)\n\tat datadog.trace.bootstrap.instrumentation.java.concurrent.Wrapper.run(Wrapper.java:25)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat java.base/java.lang.Thread.run(Thread.java:834)\n" "component" "java-web-servlet-dispatcher" + "servlet.path" "/error" "error.type" "org.springframework.http.converter.HttpMessageNotWritableException"} "metrics" {"thread.id" 62}} {"name" "spring.handler" diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/Events.java b/internal-api/src/main/java/datadog/trace/api/gateway/Events.java index 1dadc03d8b9..693a5ca7b34 100644 --- a/internal-api/src/main/java/datadog/trace/api/gateway/Events.java +++ b/internal-api/src/main/java/datadog/trace/api/gateway/Events.java @@ -138,7 +138,7 @@ public EventType>> req @SuppressWarnings("rawtypes") private static final EventType REQUEST_BODY_CONVERTED = - new ET<>("request.body.done", REQUEST_BODY_CONVERTED_ID); + new ET<>("request.body.converted", REQUEST_BODY_CONVERTED_ID); /** The request body has been converted by the framework */ @SuppressWarnings("unchecked") public EventType>> requestBodyProcessed() {