From d25059ad6bde18d2107d6636a4648dbd2fc1bff1 Mon Sep 17 00:00:00 2001 From: Jordan Wong Date: Tue, 29 Oct 2024 15:55:13 -0400 Subject: [PATCH 1/2] formatting --- .../jakarta-ws-annotations/build.gradle | 21 +++ .../jakartaws/WebServiceDecorator.java | 36 +++++ .../jakartaws/WebServiceInstrumentation.java | 106 +++++++++++++++ .../src/test/groovy/WebServiceTest.groovy | 128 ++++++++++++++++++ .../src/test/java/TestService1.java | 6 + .../src/test/java/TestService1Impl.java | 13 ++ .../src/test/java/TestService2.java | 15 ++ settings.gradle | 1 + 8 files changed, 326 insertions(+) create mode 100644 dd-java-agent/instrumentation/jakarta-ws-annotations/build.gradle create mode 100644 dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java create mode 100644 dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java create mode 100644 dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy create mode 100644 dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1.java create mode 100644 dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1Impl.java create mode 100644 dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService2.java diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/build.gradle b/dd-java-agent/instrumentation/jakarta-ws-annotations/build.gradle new file mode 100644 index 00000000000..50d4514d644 --- /dev/null +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/build.gradle @@ -0,0 +1,21 @@ + +muzzle { + pass { + group = "jakarta.jws" + module = "jakarta.jws-api" + versions = "[3.0.0,]" + } +} + +apply from: "$rootDir/gradle/java.gradle" + +addTestSuiteForDir('latestDepTest', 'test') + +dependencies { + // todo correct version non rs + compileOnly group: 'jakarta.jws', name: 'jakarta.jws-api', version: '3.0.0' + + //todo also make jakarta + testImplementation group: 'jakarta.jws', name: 'jakarta.jws-api', version: '3.0.0' + latestDepTestImplementation group: 'jakarta.jws', name: 'jakarta.jws-api', version: '+' +} diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java new file mode 100644 index 00000000000..d18fb113738 --- /dev/null +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java @@ -0,0 +1,36 @@ +package datadog.trace.instrumentation.jakartaws; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes; +import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; +import datadog.trace.bootstrap.instrumentation.decorator.BaseDecorator; + +public class WebServiceDecorator extends BaseDecorator { + public static final WebServiceDecorator DECORATE = new WebServiceDecorator(); + + public static final CharSequence JAKARTA_WS_REQUEST = + UTF8BytesString.create("jakarta-ws.request"); + public static final CharSequence JAKARTA_WS_ENDPOINT = + UTF8BytesString.create("jakarta-ws-endpoint"); + + private WebServiceDecorator() {} + + @Override + protected String[] instrumentationNames() { + return new String[] {"jakarta-ws"}; + } + + @Override + protected CharSequence spanType() { + return InternalSpanTypes.SOAP; + } + + @Override + protected CharSequence component() { + return JAKARTA_WS_ENDPOINT; + } + + public void onJaxWsSpan(final AgentSpan span, final Class target, final String method) { + span.setResourceName(spanNameForMethod(target, method)); + } +} diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java new file mode 100644 index 00000000000..d49c41a9722 --- /dev/null +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java @@ -0,0 +1,106 @@ +package datadog.trace.instrumentation.jakartaws; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.declaresAnnotation; +import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.hasSuperMethod; +import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.hasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; +import static datadog.trace.instrumentation.jakartaws.WebServiceDecorator.DECORATE; +import static datadog.trace.instrumentation.jakartaws.WebServiceDecorator.JAKARTA_WS_REQUEST; +import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.bootstrap.CallDepthThreadLocalMap; +import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import jakarta.jws.WebService; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumenterModule.class) +public final class WebServiceInstrumentation extends InstrumenterModule.Tracing + implements Instrumenter.ForBootstrap, Instrumenter.ForTypeHierarchy { + private static final String WEB_SERVICE_ANNOTATION_NAME = "jakarta.jws.WebService"; + + public WebServiceInstrumentation() { + super("jakarta-ws"); + } + + @Override + protected boolean defaultEnabled() { + return true; + } + + @Override + public String hierarchyMarkerType() { + return null; // bootstrap type + } + + @Override + public ElementMatcher hierarchyMatcher() { + return hasSuperType(declaresAnnotation(named(WEB_SERVICE_ANNOTATION_NAME))); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".WebServiceDecorator", + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + isMethod() + .and(isPublic()) + .and(not(isStatic())) + .and( + hasSuperMethod( + isDeclaredBy(declaresAnnotation(named(WEB_SERVICE_ANNOTATION_NAME))))), + getClass().getName() + "$InvokeAdvice"); + } + + public static final class InvokeAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static AgentScope beginRequest( + @Advice.This Object thiz, @Advice.Origin("#m") String method) { + final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(WebService.class); + if (callDepth > 0) { + return null; + } + + AgentSpan span = startSpan(JAKARTA_WS_REQUEST); + span.setMeasured(true); + DECORATE.onJaxWsSpan(span, thiz.getClass(), method); + DECORATE.afterStart(span); + return activateSpan(span); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void finishRequest( + @Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable error) { + if (null == scope) { + return; + } + + CallDepthThreadLocalMap.reset(WebService.class); + + AgentSpan span = scope.span(); + if (null != error) { + DECORATE.onError(span, error); + } + DECORATE.beforeFinish(span); + scope.close(); + span.finish(); + } + } +} diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy new file mode 100644 index 00000000000..3c9798b1a36 --- /dev/null +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy @@ -0,0 +1,128 @@ +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.DDSpanTypes + +import static org.junit.Assert.fail + +class WebServiceTest extends AgentTestRunner { + + @Override + void configurePreAgent() { + super.configurePreAgent() + // todo figure out sysconfig + // injectSysConfig("dd.integration.jax-ws.enabled", "true") + injectSysConfig("dd.integration.jakarta-ws.enabled", "true") + } + + def "test successful interface request is traced"() { + when: + new TestService1Impl().send("success") + + then: + assertTraces(1) { + trace(1) { + span { + operationName "jakarta-ws.request" + resourceName "TestService1Impl.send" + spanType DDSpanTypes.SOAP + errored false + parent() + tags { + "component" "jakarta-ws-endpoint" + defaultTags() + } + } + } + } + } + + def "test successful class request is traced"() { + when: + new TestService2().send("success") + + then: + assertTraces(1) { + trace(1) { + span { + operationName "jakarta-ws.request" + resourceName "TestService2.send" + spanType DDSpanTypes.SOAP + errored false + parent() + tags { + "component" "jakarta-ws-endpoint" + defaultTags() + } + } + } + } + } + + def "test failing interface request is traced"() { + when: + try { + new TestService1Impl().send("fail") + fail("expected exception") + } catch (IllegalArgumentException e) { + // expected + } + + then: + assertTraces(1) { + trace(1) { + span { + operationName "jakarta-ws.request" + resourceName "TestService1Impl.send" + spanType DDSpanTypes.SOAP + errored true + parent() + tags { + "component" "jakarta-ws-endpoint" + "error.message" "bad request" + "error.type" IllegalArgumentException.name + "error.stack" String + defaultTags() + } + } + } + } + } + + def "test failing class request is traced"() { + when: + try { + new TestService2().send("fail") + fail("expected exception") + } catch (IllegalArgumentException e) { + // expected + } + + then: + assertTraces(1) { + trace(1) { + span { + operationName "jakarta-ws.request" + resourceName "TestService2.send" + spanType DDSpanTypes.SOAP + errored true + parent() + tags { + "component" "jakarta-ws-endpoint" + "error.message" "bad request" + "error.type" IllegalArgumentException.name + "error.stack" String + defaultTags() + } + } + } + } + } + + def "test other methods are not traced"() { + when: + new TestService1Impl().random() + new TestService2().random() + + then: + assertTraces(0) {} + } +} diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1.java b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1.java new file mode 100644 index 00000000000..e46ca7e6b43 --- /dev/null +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1.java @@ -0,0 +1,6 @@ +import jakarta.jws.WebService; + +@WebService +public interface TestService1 { + String send(String message); +} diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1Impl.java b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1Impl.java new file mode 100644 index 00000000000..d564aa3bc92 --- /dev/null +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService1Impl.java @@ -0,0 +1,13 @@ +public class TestService1Impl implements TestService1 { + @Override + public String send(final String request) { + if ("fail".equals(request)) { + throw new IllegalArgumentException("bad request"); + } + return random(); + } + + public String random() { + return Double.toHexString(Math.random()); + } +} diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService2.java b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService2.java new file mode 100644 index 00000000000..3510db5c05c --- /dev/null +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/java/TestService2.java @@ -0,0 +1,15 @@ +import jakarta.jws.WebService; + +@WebService +public class TestService2 { + public String send(final String request) { + if ("fail".equals(request)) { + throw new IllegalArgumentException("bad request"); + } + return random(); + } + + protected String random() { + return Double.toHexString(Math.random()); + } +} diff --git a/settings.gradle b/settings.gradle index f2c5f11f343..b9c3868d215 100644 --- a/settings.gradle +++ b/settings.gradle @@ -269,6 +269,7 @@ include ':dd-java-agent:instrumentation:jackson-core:jackson-core-2.16' include ':dd-java-agent:instrumentation:jacoco' include ':dd-java-agent:instrumentation:jakarta-jms' include ':dd-java-agent:instrumentation:jakarta-rs-annotations-3' +include ':dd-java-agent:instrumentation:jakarta-ws-annotations' include ':dd-java-agent:instrumentation:java-concurrent' include ':dd-java-agent:instrumentation:java-concurrent:java-completablefuture' include ':dd-java-agent:instrumentation:java-concurrent:java-concurrent-21' From 24790e48f2d08ddb7160cdba4f0f8c11ecd19a9a Mon Sep 17 00:00:00 2001 From: Jordan Wong Date: Wed, 30 Oct 2024 14:28:18 -0400 Subject: [PATCH 2/2] Rename method jax -> jakarta, remove unecessary enable config --- .../instrumentation/jakartaws/WebServiceDecorator.java | 2 +- .../jakartaws/WebServiceInstrumentation.java | 7 +------ .../src/test/groovy/WebServiceTest.groovy | 8 -------- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java index d18fb113738..1364b4b6536 100644 --- a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceDecorator.java @@ -30,7 +30,7 @@ protected CharSequence component() { return JAKARTA_WS_ENDPOINT; } - public void onJaxWsSpan(final AgentSpan span, final Class target, final String method) { + public void onJakartaWsSpan(final AgentSpan span, final Class target, final String method) { span.setResourceName(spanNameForMethod(target, method)); } } diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java index d49c41a9722..ff5f9de2e6d 100644 --- a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/main/java/datadog/trace/instrumentation/jakartaws/WebServiceInstrumentation.java @@ -34,11 +34,6 @@ public WebServiceInstrumentation() { super("jakarta-ws"); } - @Override - protected boolean defaultEnabled() { - return true; - } - @Override public String hierarchyMarkerType() { return null; // bootstrap type @@ -80,7 +75,7 @@ public static AgentScope beginRequest( AgentSpan span = startSpan(JAKARTA_WS_REQUEST); span.setMeasured(true); - DECORATE.onJaxWsSpan(span, thiz.getClass(), method); + DECORATE.onJakartaWsSpan(span, thiz.getClass(), method); DECORATE.afterStart(span); return activateSpan(span); } diff --git a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy index 3c9798b1a36..5b34d15fff7 100644 --- a/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy +++ b/dd-java-agent/instrumentation/jakarta-ws-annotations/src/test/groovy/WebServiceTest.groovy @@ -5,14 +5,6 @@ import static org.junit.Assert.fail class WebServiceTest extends AgentTestRunner { - @Override - void configurePreAgent() { - super.configurePreAgent() - // todo figure out sysconfig - // injectSysConfig("dd.integration.jax-ws.enabled", "true") - injectSysConfig("dd.integration.jakarta-ws.enabled", "true") - } - def "test successful interface request is traced"() { when: new TestService1Impl().send("success")