Skip to content

Commit 5258956

Browse files
authored
Support JAX-WS transaction naming (#486)
1 parent 551e642 commit 5258956

File tree

29 files changed

+415
-72
lines changed

29 files changed

+415
-72
lines changed

CHANGELOG.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616
* Introduces a new configuration option `disable_metrics` which disables the collection of metrics via a wildcard expression.
1717
* Support for HttpUrlConnection
1818
* Adds `subtype` and `action` to spans. This replaces former typing mechanism where type, subtype and action were all set through
19-
the type in an hierarchical dotted-syntax. In order to support existing API usages, dotted types are parsed into subtype and action,
20-
however `Span.createSpan` and `Span.setType` are deprecated starting this version. Instead, type-less spans can be created using the new
21-
`Span.startSpan` API and typed spans can be created using the new `Span.startSpan(String type, String subtype, String action)` API
22-
* Add support for JBoss EAP
23-
* Improving startup times
19+
the type in an hierarchical dotted-syntax. In order to support existing API usages, dotted types are parsed into subtype and action,
20+
however `Span.createSpan` and `Span.setType` are deprecated starting this version. Instead, type-less spans can be created using the new
21+
`Span.startSpan` API and typed spans can be created using the new `Span.startSpan(String type, String subtype, String action)` API
22+
* Support for JBoss EAP 6.4, 7.0, 7.1 and 7.2
23+
* Improved startup times
24+
* Support for SOAP (JAX-WS).
25+
SOAP client create spans and propagate context.
26+
Transactions are created for `@WebService` classes and `@WebMethod` methods.
2427

2528
## Bug Fixes
2629
* Fixes a failure in BitBucket when agent deployed ([#349](https://github.com/elastic/apm-agent-java/issues/349))

apm-agent-plugins/apm-jaxrs-plugin/src/main/java/co/elastic/apm/agent/jaxrs/JaxRsTransactionNameInstrumentation.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import net.bytebuddy.matcher.ElementMatcher;
3232
import net.bytebuddy.matcher.ElementMatchers;
3333

34-
import java.util.Arrays;
3534
import java.util.Collection;
3635
import java.util.Collections;
3736

@@ -103,6 +102,6 @@ public ElementMatcher<? super MethodDescription> getMethodMatcher() {
103102

104103
@Override
105104
public Collection<String> getInstrumentationGroupNames() {
106-
return Arrays.asList("jax-rs", "jax-rs-annotations");
105+
return Collections.singletonList("jax-rs");
107106
}
108107
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>apm-agent-plugins</artifactId>
7+
<groupId>co.elastic.apm</groupId>
8+
<version>1.3.1-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>apm-jaxws-plugin</artifactId>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>javax</groupId>
17+
<artifactId>javaee-api</artifactId>
18+
<version>7.0</version>
19+
<scope>test</scope>
20+
</dependency>
21+
</dependencies>
22+
23+
24+
</project>
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*-
2+
* #%L
3+
* Elastic APM Java agent
4+
* %%
5+
* Copyright (C) 2018 - 2019 Elastic and contributors
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package co.elastic.apm.agent.jaxws;
21+
22+
import co.elastic.apm.agent.bci.ElasticApmInstrumentation;
23+
import co.elastic.apm.agent.bci.bytebuddy.SimpleMethodSignatureOffsetMappingFactory.SimpleMethodSignature;
24+
import co.elastic.apm.agent.impl.ElasticApmTracer;
25+
import co.elastic.apm.agent.impl.stacktrace.StacktraceConfiguration;
26+
import co.elastic.apm.agent.impl.transaction.Transaction;
27+
import net.bytebuddy.asm.Advice;
28+
import net.bytebuddy.description.NamedElement;
29+
import net.bytebuddy.description.method.MethodDescription;
30+
import net.bytebuddy.description.type.TypeDescription;
31+
import net.bytebuddy.matcher.ElementMatcher;
32+
import net.bytebuddy.matcher.ElementMatchers;
33+
34+
import java.util.Collection;
35+
import java.util.Collections;
36+
37+
import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.classLoaderCanLoadClass;
38+
import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.isInAnyPackage;
39+
import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.overridesOrImplementsMethodThat;
40+
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
41+
import static net.bytebuddy.matcher.ElementMatchers.isBootstrapClassLoader;
42+
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
43+
import static net.bytebuddy.matcher.ElementMatchers.named;
44+
import static net.bytebuddy.matcher.ElementMatchers.not;
45+
46+
public class JaxWsTransactionNameInstrumentation extends ElasticApmInstrumentation {
47+
48+
private Collection<String> applicationPackages = Collections.emptyList();
49+
50+
@Advice.OnMethodEnter(suppress = Throwable.class)
51+
private static void setTransactionName(@SimpleMethodSignature String signature) {
52+
if (tracer != null) {
53+
final Transaction transaction = tracer.currentTransaction();
54+
if (transaction != null && transaction.getName().length() == 0) {
55+
transaction.withName(signature);
56+
}
57+
}
58+
}
59+
60+
@Override
61+
public void init(ElasticApmTracer tracer) {
62+
applicationPackages = tracer.getConfig(StacktraceConfiguration.class).getApplicationPackages();
63+
}
64+
65+
@Override
66+
public ElementMatcher<? super NamedElement> getTypeMatcherPreFilter() {
67+
// setting application_packages makes this matcher more performant but is not required
68+
// could lead to false negative matches when importing a 3rd party library whose JAX-WS resources are exposed
69+
return isInAnyPackage(applicationPackages, ElementMatchers.<NamedElement>any());
70+
}
71+
72+
@Override
73+
public ElementMatcher<? super TypeDescription> getTypeMatcher() {
74+
// the implementations have to be annotated as well
75+
// quote from javadoc:
76+
// "Marks a Java class as implementing a Web Service, or a Java interface as defining a Web Service interface."
77+
return isAnnotatedWith(named("javax.jws.WebService")).and(not(isInterface()));
78+
}
79+
80+
@Override
81+
public ElementMatcher.Junction<ClassLoader> getClassLoaderMatcher() {
82+
return not(isBootstrapClassLoader())
83+
.and(classLoaderCanLoadClass("javax.jws.WebService"));
84+
}
85+
86+
@Override
87+
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
88+
return overridesOrImplementsMethodThat(
89+
isAnnotatedWith(
90+
named("javax.jws.WebMethod")))
91+
.onSuperClassesThat(isInAnyPackage(applicationPackages, ElementMatchers.<NamedElement>any()));
92+
}
93+
94+
@Override
95+
public Collection<String> getInstrumentationGroupNames() {
96+
return Collections.singletonList("jax-ws");
97+
}
98+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*-
2+
* #%L
3+
* Elastic APM Java agent
4+
* %%
5+
* Copyright (C) 2018 - 2019 Elastic and contributors
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
@NonnullApi
21+
package co.elastic.apm.agent.jaxws;
22+
23+
import co.elastic.apm.agent.annotation.NonnullApi;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
co.elastic.apm.agent.jaxws.JaxWsTransactionNameInstrumentation
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*-
2+
* #%L
3+
* Elastic APM Java agent
4+
* %%
5+
* Copyright (C) 2018 - 2019 Elastic and contributors
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package co.elastic.apm.agent.jaxws;
21+
22+
import co.elastic.apm.agent.AbstractInstrumentationTest;
23+
import co.elastic.apm.agent.impl.Scope;
24+
import co.elastic.apm.agent.impl.transaction.Transaction;
25+
import org.junit.jupiter.api.BeforeEach;
26+
import org.junit.jupiter.api.Test;
27+
28+
import javax.jws.WebMethod;
29+
import javax.jws.WebService;
30+
import javax.jws.soap.SOAPBinding;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
class JaxWsTransactionNameInstrumentationTest extends AbstractInstrumentationTest {
35+
36+
private HelloWorldService helloWorldService;
37+
38+
@BeforeEach
39+
void setUp() {
40+
helloWorldService = new HelloWorldServiceImpl();
41+
}
42+
43+
@Test
44+
void testTransactionName() {
45+
final Transaction transaction = tracer.startTransaction();
46+
try (Scope scope = transaction.activateInScope()) {
47+
helloWorldService.sayHello();
48+
} finally {
49+
transaction.end();
50+
}
51+
assertThat(transaction.getName().toString()).isEqualTo("HelloWorldServiceImpl#sayHello");
52+
}
53+
54+
@SOAPBinding(style = SOAPBinding.Style.RPC)
55+
@WebService(targetNamespace = "elastic")
56+
public interface HelloWorldService {
57+
@WebMethod
58+
String sayHello();
59+
}
60+
61+
@WebService(serviceName = "HelloWorldService", portName = "HelloWorld", name = "HelloWorld",
62+
endpointInterface = "co.elastic.apm.agent.jaxws.JaxWsTransactionNameInstrumentationTest.HelloWorldService",
63+
targetNamespace = "elastic")
64+
public static class HelloWorldServiceImpl implements HelloWorldService {
65+
@Override
66+
public String sayHello() {
67+
return "Hello World";
68+
}
69+
}
70+
71+
}

apm-agent-plugins/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<module>apm-okhttp-plugin</module>
2525
<module>apm-java-concurrent-plugin</module>
2626
<module>apm-urlconnection-plugin</module>
27+
<module>apm-jaxws-plugin</module>
2728
</modules>
2829

2930
<properties>

docs/supported-technologies.asciidoc

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,26 +45,30 @@ the agent does not capture transactions.
4545
[[supported-web-frameworks]]
4646
=== Web Frameworks
4747
|===
48-
|Framework |Supported versions | Description
48+
|Framework |Supported versions | Description | Since
4949

5050
|Servlet API
5151
|3+
5252
|A transaction will be created for all incoming HTTP requests to your Servlet API-based application.
5353
See also <<supported-app-servers>>
54+
|1.0.0
5455

5556
|Spring Web MVC
5657
|4.x, 5.x
5758
|If you are using Spring MVC (for example with Spring Boot),
5859
the transactions are named based on your controllers (`ControllerClass#controllerMethod`).
60+
|1.0.0
5961

6062
|JavaServer Faces
6163
|2.2.x, 2.3.x
6264
|If you are using JSF, transactions are named based on the requested Facelets and spans are captured for visibility into execution and
6365
rendering
66+
|1.0.0
6467

6568
|Spring Boot
6669
|1.5+, 2.x
6770
|Supports embedded Tomcat, Jetty and Undertow
71+
|1.0.0
6872

6973
|JAX-RS
7074
|2.x
@@ -75,6 +79,18 @@ rendering
7579
This comes at the cost of increased startup times, however.
7680

7781
Note: JAX-RS is only supported when running on a supported <<supported-app-servers, Application Server/Servlet Container>>.
82+
|1.0.0
83+
84+
|JAX-WS
85+
|
86+
|The transactions are named based on your `@javax.jws.WebService` annotated classes and `@javax.jws.WebMethod` annotated method names (`WebServiceClass#webMethod`).
87+
Note that only the packages configured in <<config-application-packages>> are scanned for JAX-WS resources.
88+
If you don't set this option,
89+
all classes are scanned.
90+
This comes at the cost of increased startup times, however.
91+
92+
Note: JAX-WS is only supported when running on a supported <<supported-app-servers, Application Server/Servlet Container>> and when using the HTTP binding.
93+
|1.4.0
7894

7995
|===
8096

@@ -168,6 +184,12 @@ The spans are named after the schema `<method> <host>`, for example `GET elastic
168184
|
169185
| 1.4.0
170186

187+
|JAX-WS client
188+
|
189+
|JAX-WS clients created via link:https://docs.oracle.com/javaee/7/api/javax/xml/ws/Service.html[`javax.xml.ws.Service`]
190+
inherently support context propagation as they are using `HttpUrlConnection` underneath.
191+
|1.4.0
192+
171193
|===
172194

173195

@@ -193,10 +215,10 @@ This section lists all supported asynchronous frameworks.
193215
[float]
194216
[[supported-technologies-caveats]]
195217
=== Caveats
196-
* Tracing of asynchronous invocations (for example `java.util.concurrent.ExecutorService`) is currently not supported.
197218
* Certain OSGi containers need the following configuration setting in case you see exceptions like
198219
`java.lang.NoClassDefFoundError: co/elastic/apm/jdbc/StatementInstrumentation`:
199220
`org.osgi.framework.bootdelegation=co.elastic.apm.agent.*`
200221
* Other JVM languages, like Scala, Kotlin and Groovy have not been tested yet.
201222
* The agent does currently not support running on JVMs with an enabled `SecurityManager`.
202-
You may see exceptions like this: `java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getProtectionDomain")`
223+
You may see exceptions like this: `java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getProtectionDomain")`.
224+
Try to grant `java.security.AllPermission` to the agent.

elastic-apm-agent/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@
162162
<artifactId>apm-jaxrs-plugin</artifactId>
163163
<version>${project.version}</version>
164164
</dependency>
165+
<dependency>
166+
<groupId>${project.groupId}</groupId>
167+
<artifactId>apm-jaxws-plugin</artifactId>
168+
<version>${project.version}</version>
169+
</dependency>
165170
<dependency>
166171
<groupId>${project.groupId}</groupId>
167172
<artifactId>apm-jdbc-plugin</artifactId>

0 commit comments

Comments
 (0)