-
Notifications
You must be signed in to change notification settings - Fork 870
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add instrumentation for jaxws metro 3.0+
Previously, only jaxws metro 2.2 was instrumented, which only worked with Java EE (javax namespace). Now, jaxws metro 3.0+ is also instrumented, which works with Jakarta EE (jakarta namespace). Rather than copy/pasting the metro 2.2 instrumentation implementation to a new metro 3.0 module, I made the existing module able to work with both Java EE and Jakarta EE classes. More specifically, I * moved the instrumentation implementation from `jaxws-2.0-metro-2.2` to `jaxws-metro-2.2` since "jaxws-2.0" is specific to Java EE. * Renamed `MetroServerSpanNaming` to `MetroServerSpanNameUpdater`, and made it work with both Java EE and Jakarta EE based on what is available on the runtime classpath. * moved the Java EE specific tests from `jaxws-2.0-metro-2.2` to `jaxws-2.0-metro-2.2-testing` * added new Jakarta EE specific tests in `jaxws-3.0-metro-2.2-testing`. This is basically a copy/paste of the tests from `jaxws-2.0-metro-2.2-testing`, but using Jakarta EE namespacing. * added the `jaxws-3.0-common-testing` module for reusable Jakarta EE tests for other future jaxws instrumentation implementations. This is basically a copy/paste of `jaxws-2.0-common-testing`, but using Jakarta EE namespacing. Regarding the implementation of `MetroServerSpanNameUpdater`, I originally added compile time dependencies on both `jakarta.servlet-api` and `javax.servlet-api`, and referenced both of their classes directly in the code, although guarded to make sure things would still work if they weren't on the runtime classpath. Unfortunately, muzzle would disable the instrumentation if either was not found at runtime. Therefore, I had to refactor the code a bit to only use reflection to access the classes. This way muzzle won't disable the instrumentation if either is not found. This is related to #9569, but specific to the metro runtime, rather than at the annotated `@WebService` level.
- Loading branch information
Showing
26 changed files
with
571 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
instrumentation/jaxws/jaxws-2.0-metro-2.2-testing/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
plugins { | ||
id("otel.javaagent-testing") | ||
} | ||
|
||
dependencies { | ||
testImplementation("javax.servlet:javax.servlet-api:3.0.1") | ||
testImplementation("com.sun.xml.ws:jaxws-rt:2.3.6") | ||
|
||
testImplementation(project(":instrumentation:jaxws:jaxws-2.0-common-testing")) | ||
|
||
testInstrumentation(project(":instrumentation:jaxws:jaxws-metro-2.2:javaagent")) | ||
testInstrumentation(project(":instrumentation:jaxws:jaxws-2.0:javaagent")) | ||
testInstrumentation(project(":instrumentation:jaxws:jaxws-jws-api-1.1:javaagent")) | ||
|
||
testInstrumentation(project(":instrumentation:servlet:servlet-3.0:javaagent")) | ||
testInstrumentation(project(":instrumentation:jetty:jetty-8.0:javaagent")) | ||
|
||
latestDepTestLibrary("com.sun.xml.ws:jaxws-rt:2.+") | ||
latestDepTestLibrary("com.sun.xml.stream.buffer:streambuffer:1.+") | ||
} | ||
|
||
tasks.withType<Test>().configureEach { | ||
// required on jdk17 | ||
jvmArgs("--add-exports=java.xml/com.sun.org.apache.xerces.internal.dom=ALL-UNNAMED") | ||
jvmArgs("--add-exports=java.xml/com.sun.org.apache.xerces.internal.jaxp=ALL-UNNAMED") | ||
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") | ||
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
53 changes: 0 additions & 53 deletions
53
...src/main/java/io/opentelemetry/javaagent/instrumentation/metro/MetroServerSpanNaming.java
This file was deleted.
Oops, something went wrong.
28 changes: 28 additions & 0 deletions
28
instrumentation/jaxws/jaxws-3.0-common-testing/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
plugins { | ||
id("org.unbroken-dome.xjc") | ||
id("otel.java-conventions") | ||
} | ||
|
||
tasks { | ||
named<Checkstyle>("checkstyleMain") { | ||
// exclude generated web service classes | ||
exclude("**/hello_web_service/**") | ||
} | ||
} | ||
|
||
dependencies { | ||
api("jakarta.xml.ws:jakarta.xml.ws-api:3.0.0") | ||
api("jakarta.jws:jakarta.jws-api:3.0.0") | ||
|
||
api("ch.qos.logback:logback-classic") | ||
api("org.slf4j:log4j-over-slf4j") | ||
api("org.slf4j:jcl-over-slf4j") | ||
api("org.slf4j:jul-to-slf4j") | ||
api("org.eclipse.jetty:jetty-webapp:11.0.17") | ||
api("org.springframework.ws:spring-ws-core:4.0.0") | ||
|
||
implementation(project(":testing-common")) | ||
|
||
xjcTool("com.sun.xml.bind:jaxb-xjc:3.0.2") | ||
xjcTool("com.sun.xml.bind:jaxb-impl:3.0.2") | ||
} |
187 changes: 187 additions & 0 deletions
187
instrumentation/jaxws/jaxws-3.0-common-testing/src/main/groovy/AbstractJaxWsTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification | ||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert | ||
import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait | ||
import io.opentelemetry.sdk.trace.data.SpanData | ||
import io.opentelemetry.semconv.SemanticAttributes | ||
import io.opentelemetry.test.hello_web_service.Hello2Request | ||
import io.opentelemetry.test.hello_web_service.HelloRequest | ||
import org.eclipse.jetty.server.Server | ||
import org.eclipse.jetty.util.resource.Resource | ||
import org.eclipse.jetty.webapp.WebAppContext | ||
import org.springframework.oxm.jaxb.Jaxb2Marshaller | ||
import org.springframework.util.ClassUtils | ||
import org.springframework.ws.client.core.WebServiceTemplate | ||
import org.springframework.ws.soap.client.SoapFaultClientException | ||
import spock.lang.Shared | ||
import spock.lang.Unroll | ||
|
||
import static io.opentelemetry.api.trace.SpanKind.INTERNAL | ||
import static io.opentelemetry.api.trace.SpanKind.SERVER | ||
import static io.opentelemetry.api.trace.StatusCode.ERROR | ||
|
||
abstract class AbstractJaxWsTest extends AgentInstrumentationSpecification implements HttpServerTestTrait<Server> { | ||
|
||
@Shared | ||
private Jaxb2Marshaller marshaller = new Jaxb2Marshaller() | ||
|
||
@Shared | ||
protected WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marshaller) | ||
|
||
def setupSpec() { | ||
setupServer() | ||
|
||
marshaller.setPackagesToScan(ClassUtils.getPackageName(HelloRequest)) | ||
marshaller.afterPropertiesSet() | ||
} | ||
|
||
def cleanupSpec() { | ||
cleanupServer() | ||
} | ||
|
||
@Override | ||
Server startServer(int port) { | ||
WebAppContext webAppContext = new WebAppContext() | ||
webAppContext.setContextPath(getContextPath()) | ||
// set up test application | ||
webAppContext.setBaseResource(Resource.newSystemResource("test-app")) | ||
webAppContext.getMetaData().addWebInfResource(Resource.newClassPathResource("/")) | ||
|
||
def jettyServer = new Server(port) | ||
jettyServer.connectors.each { | ||
it.setHost('localhost') | ||
} | ||
|
||
jettyServer.setHandler(webAppContext) | ||
jettyServer.start() | ||
|
||
return jettyServer | ||
} | ||
|
||
@Override | ||
void stopServer(Server server) { | ||
server.stop() | ||
server.destroy() | ||
} | ||
|
||
@Override | ||
String getContextPath() { | ||
return "/jetty-context" | ||
} | ||
|
||
String getServiceAddress(String serviceName) { | ||
return address.resolve("ws/" + serviceName).toString() | ||
} | ||
|
||
def makeRequest(methodName, name) { | ||
Object request = null | ||
if ("hello" == methodName) { | ||
request = new HelloRequest(name: name) | ||
} else if ("hello2" == methodName) { | ||
request = new Hello2Request(name: name) | ||
} else { | ||
throw new IllegalArgumentException(methodName) | ||
} | ||
|
||
return webServiceTemplate.marshalSendAndReceive(getServiceAddress("HelloService"), request) | ||
} | ||
|
||
@Unroll | ||
def "test #methodName"() { | ||
setup: | ||
def response = makeRequest(methodName, "Test") | ||
|
||
expect: | ||
response.getMessage() == "Hello Test" | ||
|
||
and: | ||
def spanCount = 2 | ||
assertTraces(1) { | ||
trace(0, spanCount) { | ||
serverSpan(it, 0, serverSpanName(methodName)) | ||
handlerSpan(it, 1, methodName, span(0)) | ||
} | ||
} | ||
|
||
where: | ||
methodName << ["hello", "hello2"] | ||
} | ||
|
||
@Unroll | ||
def "test #methodName exception"() { | ||
when: | ||
makeRequest(methodName, "exception") | ||
|
||
then: | ||
def error = thrown(SoapFaultClientException) | ||
error.getMessage() == "hello exception" | ||
|
||
and: | ||
def spanCount = 2 | ||
def expectedException = new Exception("hello exception") | ||
assertTraces(1) { | ||
trace(0, spanCount) { | ||
serverSpan(it, 0, serverSpanName(methodName), expectedException) | ||
handlerSpan(it, 1, methodName, span(0), expectedException) | ||
} | ||
} | ||
|
||
where: | ||
methodName << ["hello", "hello2"] | ||
} | ||
|
||
def serverSpanName(String operation) { | ||
return getContextPath() + "/ws/HelloService/" + operation | ||
} | ||
|
||
static serverSpan(TraceAssert trace, int index, String operation, Throwable exception = null) { | ||
trace.span(index) { | ||
hasNoParent() | ||
name operation | ||
kind SERVER | ||
if (exception != null) { | ||
status ERROR | ||
} | ||
} | ||
} | ||
|
||
static handlerSpan(TraceAssert trace, int index, String operation, Object parentSpan = null, Throwable exception = null) { | ||
trace.span(index) { | ||
if (parentSpan == null) { | ||
hasNoParent() | ||
} else { | ||
childOf((SpanData) parentSpan) | ||
} | ||
name "HelloService/" + operation | ||
kind INTERNAL | ||
if (exception) { | ||
status ERROR | ||
errorEvent(exception.class, exception.message) | ||
} | ||
} | ||
} | ||
|
||
static annotationHandlerSpan(TraceAssert trace, int index, String methodName, Object parentSpan = null, Throwable exception = null) { | ||
trace.span(index) { | ||
if (parentSpan == null) { | ||
hasNoParent() | ||
} else { | ||
childOf((SpanData) parentSpan) | ||
} | ||
name "HelloServiceImpl." + methodName | ||
kind INTERNAL | ||
if (exception) { | ||
status ERROR | ||
errorEvent(exception.class, exception.message) | ||
} | ||
attributes { | ||
"$SemanticAttributes.CODE_NAMESPACE" "hello.HelloServiceImpl" | ||
"$SemanticAttributes.CODE_FUNCTION" methodName | ||
} | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
instrumentation/jaxws/jaxws-3.0-common-testing/src/main/groovy/hello/BaseHelloService.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package hello | ||
|
||
class BaseHelloService { | ||
|
||
String hello2(String name) { | ||
if ("exception" == name) { | ||
throw new Exception("hello exception") | ||
} | ||
return "Hello " + name | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
instrumentation/jaxws/jaxws-3.0-common-testing/src/main/groovy/hello/HelloService.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package hello | ||
|
||
import jakarta.jws.WebParam | ||
import jakarta.jws.WebResult | ||
import jakarta.jws.WebService | ||
import jakarta.xml.ws.RequestWrapper | ||
|
||
@WebService(targetNamespace = "http://opentelemetry.io/test/hello-web-service") | ||
interface HelloService { | ||
|
||
@RequestWrapper(localName = "helloRequest") | ||
@WebResult(name = "message") | ||
String hello(@WebParam(name = "name") String name) | ||
|
||
@RequestWrapper(localName = "hello2Request") | ||
@WebResult(name = "message") | ||
String hello2(@WebParam(name = "name") String name) | ||
|
||
} |
19 changes: 19 additions & 0 deletions
19
instrumentation/jaxws/jaxws-3.0-common-testing/src/main/groovy/hello/HelloServiceImpl.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package hello | ||
|
||
import jakarta.jws.WebService | ||
|
||
@WebService(serviceName = "HelloService", endpointInterface = "hello.HelloService", targetNamespace = "http://opentelemetry.io/test/hello-web-service") | ||
class HelloServiceImpl extends BaseHelloService implements HelloService { | ||
|
||
String hello(String name) { | ||
if ("exception" == name) { | ||
throw new Exception("hello exception") | ||
} | ||
return "Hello " + name | ||
} | ||
} |
Oops, something went wrong.