Skip to content

Commit 6baa4a7

Browse files
authored
Add support for RESTEasy 6.x (#587)
1 parent fbabc3d commit 6baa4a7

File tree

23 files changed

+1197
-2
lines changed

23 files changed

+1197
-2
lines changed

.github/workflows/plugins-jdk17-test.1.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ jobs:
5656
matrix:
5757
case:
5858
- spring-6.x-scenario
59+
- resteasy-6.x-scenario
5960
steps:
6061
- uses: actions/checkout@v2
6162
with:

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ Callable {
148148
* Upgrade netty-codec-http2 to 4.1.94.Final
149149
* Upgrade guava to 32.0.1
150150
* Fix issue with duplicate enhancement by ThreadPoolExecutor
151+
* Add plugin to support for RESTeasy 6.x.
151152

152153
#### Documentation
153154

apm-sniffer/apm-sdk-plugin/resteasy-plugin/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<modules>
2929
<module>resteasy-server-3.x-plugin</module>
3030
<module>resteasy-server-4.x-plugin</module>
31+
<module>resteasy-server-6.x-plugin</module>
3132
</modules>
3233

3334
<packaging>pom</packaging>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to You under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
~
18+
-->
19+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21+
<modelVersion>4.0.0</modelVersion>
22+
<parent>
23+
<artifactId>resteasy-plugin</artifactId>
24+
<groupId>org.apache.skywalking</groupId>
25+
<version>9.0.0-SNAPSHOT</version>
26+
</parent>
27+
28+
<artifactId>resteasy-server-6.x-plugin</artifactId>
29+
<packaging>jar</packaging>
30+
31+
<name>apm-resteasy-server-6.x-plugin</name>
32+
33+
<properties>
34+
<resteasy.version>6.2.4.Final</resteasy.version>
35+
</properties>
36+
37+
<dependencies>
38+
<dependency>
39+
<groupId>org.jboss.resteasy</groupId>
40+
<artifactId>resteasy-core</artifactId>
41+
<version>${resteasy.version}</version>
42+
<scope>provided</scope>
43+
</dependency>
44+
</dependencies>
45+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.resteasy.v6.server;
20+
21+
import org.apache.skywalking.apm.agent.core.context.ContextManager;
22+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
25+
import org.jboss.resteasy.spi.HttpRequest;
26+
27+
import java.lang.reflect.Method;
28+
29+
public class SynchronousDispatcherExceptionInterceptor implements InstanceMethodsAroundInterceptor {
30+
31+
@Override
32+
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
33+
MethodInterceptResult result) throws Throwable {
34+
if (ContextManager.isActive() && !((HttpRequest) allArguments[0]).getAsyncContext().isSuspended()) {
35+
ContextManager.activeSpan().log((Throwable) allArguments[2]);
36+
}
37+
}
38+
39+
@Override
40+
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
41+
Object ret) throws Throwable {
42+
return ret;
43+
}
44+
45+
@Override
46+
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
47+
Class<?>[] argumentsTypes, Throwable t) {
48+
if (ContextManager.isActive()) {
49+
ContextManager.activeSpan().log(t);
50+
}
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.resteasy.v6.server;
20+
21+
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
22+
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
23+
import org.apache.skywalking.apm.agent.core.context.ContextManager;
24+
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
25+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
26+
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
27+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
28+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
29+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
30+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
31+
import org.jboss.resteasy.spi.HttpRequest;
32+
import org.jboss.resteasy.spi.HttpResponse;
33+
import org.slf4j.Logger;
34+
import org.slf4j.LoggerFactory;
35+
36+
import java.lang.reflect.Method;
37+
38+
public class SynchronousDispatcherInterceptor implements InstanceMethodsAroundInterceptor {
39+
private static final Logger LOG = LoggerFactory.getLogger(SynchronousDispatcherInterceptor.class);
40+
41+
@Override
42+
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
43+
MethodInterceptResult result) throws Throwable {
44+
HttpRequest request = (HttpRequest) allArguments[0];
45+
46+
ContextCarrier contextCarrier = new ContextCarrier();
47+
CarrierItem next = contextCarrier.items();
48+
while (next.hasNext()) {
49+
next = next.next();
50+
next.setHeadValue(request.getHttpHeaders().getHeaderString(next.getHeadKey()));
51+
}
52+
53+
String operationName = request.getHttpMethod() + ":" + request.getUri().getPath();
54+
AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
55+
span.tag(Tags.URL, toPath(request.getUri().getRequestUri().toString()));
56+
span.tag(Tags.HTTP.METHOD, request.getHttpMethod());
57+
span.setComponent(ComponentsDefine.RESTEASY);
58+
SpanLayer.asHttp(span);
59+
}
60+
61+
@Override
62+
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
63+
Object ret) throws Throwable {
64+
if (!ContextManager.isActive()) {
65+
return ret;
66+
}
67+
HttpResponse response = (HttpResponse) allArguments[1];
68+
AbstractSpan span = ContextManager.activeSpan();
69+
if (response.getStatus() >= 400) {
70+
span.errorOccurred();
71+
}
72+
Tags.HTTP_RESPONSE_STATUS_CODE.set(span, response.getStatus());
73+
ContextManager.stopSpan();
74+
return ret;
75+
}
76+
77+
@Override
78+
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
79+
Class<?>[] argumentsTypes, Throwable t) {
80+
if (ContextManager.isActive()) {
81+
ContextManager.activeSpan().log(t);
82+
}
83+
}
84+
85+
private static String toPath(String uri) {
86+
int index = uri.indexOf("?");
87+
if (index > -1) {
88+
return uri.substring(0, index);
89+
} else {
90+
return uri;
91+
}
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.resteasy.v6.server.define;
20+
21+
import net.bytebuddy.description.method.MethodDescription;
22+
import net.bytebuddy.matcher.ElementMatcher;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
26+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
27+
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
28+
29+
import static net.bytebuddy.matcher.ElementMatchers.named;
30+
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
31+
32+
public class SynchronousDispatcherInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
33+
34+
private static final String ENHANCE_CLASS = "org.jboss.resteasy.core.SynchronousDispatcher";
35+
36+
private static final String INVOKE_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.resteasy.v6.server.SynchronousDispatcherInterceptor";
37+
private static final String INVOKE_EXCEPTION_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.resteasy.v6.server.SynchronousDispatcherExceptionInterceptor";
38+
39+
@Override
40+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
41+
return null;
42+
}
43+
44+
@Override
45+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
46+
return new InstanceMethodsInterceptPoint[] {
47+
new InstanceMethodsInterceptPoint() {
48+
@Override
49+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
50+
return named("invoke").and(takesArguments(3));
51+
}
52+
53+
@Override
54+
public String getMethodsInterceptor() {
55+
return INVOKE_INTERCEPT_CLASS;
56+
}
57+
58+
@Override
59+
public boolean isOverrideArgs() {
60+
return false;
61+
}
62+
},
63+
new InstanceMethodsInterceptPoint() {
64+
@Override
65+
public ElementMatcher<MethodDescription> getMethodsMatcher() {
66+
return named("writeException").and(takesArguments(3));
67+
}
68+
69+
@Override
70+
public String getMethodsInterceptor() {
71+
return INVOKE_EXCEPTION_INTERCEPT_CLASS;
72+
}
73+
74+
@Override
75+
public boolean isOverrideArgs() {
76+
return false;
77+
}
78+
}
79+
};
80+
}
81+
82+
@Override
83+
protected ClassMatch enhanceClass() {
84+
return NameMatch.byName(ENHANCE_CLASS);
85+
}
86+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
resteasy-server-6.x=org.apache.skywalking.apm.plugin.resteasy.v6.server.define.SynchronousDispatcherInstrumentation
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.resteasy.v6.server;
20+
21+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
22+
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
23+
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef;
24+
import org.apache.skywalking.apm.agent.test.helper.SegmentRefHelper;
25+
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
26+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
27+
28+
import static org.apache.skywalking.apm.agent.test.tools.SpanAssert.assertComponent;
29+
import static org.hamcrest.CoreMatchers.is;
30+
import static org.hamcrest.MatcherAssert.assertThat;
31+
32+
class AssertTools {
33+
34+
static void assertTraceSegmentRef(TraceSegmentRef ref) {
35+
assertThat(SegmentRefHelper.getParentServiceInstance(ref), is("instance"));
36+
assertThat(SegmentRefHelper.getSpanId(ref), is(3));
37+
assertThat(SegmentRefHelper.getTraceSegmentId(ref).toString(), is("3.4.5"));
38+
}
39+
40+
static void assertHttpSpan(AbstractTracingSpan span) {
41+
assertThat(span.getOperationName(), is("GET:/test/testRequestURL"));
42+
assertComponent(span, ComponentsDefine.RESTEASY);
43+
SpanAssert.assertTag(span, 0, "http://localhost:8080/test/testRequestURL");
44+
assertThat(span.isEntry(), is(true));
45+
SpanAssert.assertLayer(span, SpanLayer.HTTP);
46+
}
47+
}

0 commit comments

Comments
 (0)