Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add instrumentation for jaxws metro 3.0+ #9705

Merged
merged 10 commits into from
Oct 27, 2023
2 changes: 1 addition & 1 deletion docs/supported-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ These are the supported libraries and frameworks:
| [Eclipse Grizzly](https://javaee.github.io/grizzly/httpserverframework.html) | 2.3+ | N/A | [HTTP Server Spans], [HTTP Server Metrics] |
| [Eclipse Jersey](https://eclipse-ee4j.github.io/jersey/) | 2.0+ (not including 3.x yet) | N/A | Provides `http.route` [2], Controller Spans [3] |
| [Eclipse Jetty HTTP Client](https://www.eclipse.org/jetty/javadoc/jetty-9/org/eclipse/jetty/client/HttpClient.html) | 9.2+ (not including 10+ yet) | [opentelemetry-jetty-httpclient-9.2](../instrumentation/jetty-httpclient/jetty-httpclient-9.2/library) | [HTTP Client Spans], [HTTP Client Metrics] |
| [Eclipse Metro](https://projects.eclipse.org/projects/ee4j.metro) | 2.2+ (not including 3.x yet) | N/A | Provides `http.route` [2], Controller Spans [3] |
| [Eclipse Metro](https://projects.eclipse.org/projects/ee4j.metro) | 2.2+ | N/A | Provides `http.route` [2], Controller Spans [3] |
| [Eclipse Mojarra](https://projects.eclipse.org/projects/ee4j.mojarra) | 1.2+ (not including 3.x yet) | N/A | Provides `http.route` [2], Controller Spans [3] |
| [Elasticsearch API Client](https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html) | 7.16+ and 8.0+ | N/A | [Elasticsearch Client Spans] |
| [Elasticsearch REST Client](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html) | 5.0+ | N/A | [Database Client Spans] |
Expand Down
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")
philsttr marked this conversation as resolved.
Show resolved Hide resolved

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")
}

This file was deleted.

28 changes: 28 additions & 0 deletions instrumentation/jaxws/jaxws-3.0-common-testing/build.gradle.kts
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")
philsttr marked this conversation as resolved.
Show resolved Hide resolved
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")
}
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
}
}
}
}
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
}
}
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)

}
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
}
}
Loading
Loading