diff --git a/.gitignore b/.gitignore
index 1a468655b..bdc57edb2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ target/
.DS_Store
*~
packages/
+**/dependency-reduced-pom.xml
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/ControllerServiceMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/AbstractMethodInteceptor.java
similarity index 73%
rename from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/ControllerServiceMethodInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/AbstractMethodInteceptor.java
index 08967f935..a96f94a78 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/ControllerServiceMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/AbstractMethodInteceptor.java
@@ -1,8 +1,5 @@
package org.skywalking.apm.plugin.spring.mvc;
-import java.lang.reflect.Method;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import org.skywalking.apm.agent.core.context.CarrierItem;
import org.skywalking.apm.agent.core.context.ContextCarrier;
import org.skywalking.apm.agent.core.context.ContextManager;
@@ -13,33 +10,30 @@ import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.skywalking.apm.network.trace.component.ComponentsDefine;
-import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+
/**
- * The ControllerServiceMethodInterceptor only use the first mapping value.
+ * the abstract method inteceptor
*/
-public class ControllerServiceMethodInterceptor implements InstanceMethodsAroundInterceptor {
+public abstract class AbstractMethodInteceptor implements InstanceMethodsAroundInterceptor {
+ public abstract String getRequestURL(Method method);
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- MethodInterceptResult result) throws Throwable {
+ MethodInterceptResult result) throws Throwable {
PathMappingCache pathMappingCache = (PathMappingCache)objInst.getSkyWalkingDynamicField();
String requestURL = pathMappingCache.findPathMapping(method);
if (requestURL == null) {
- RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
- if (methodRequestMapping.value().length > 0) {
- requestURL = methodRequestMapping.value()[0];
- } else if (methodRequestMapping.path().length > 0) {
- requestURL = methodRequestMapping.path()[0];
- } else {
- requestURL = "";
- }
+ requestURL = getRequestURL(method);
pathMappingCache.addPathMapping(method, requestURL);
requestURL = pathMappingCache.findPathMapping(method);
}
- HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
@@ -57,7 +51,7 @@ public class ControllerServiceMethodInterceptor implements InstanceMethodsAround
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
- Object ret) throws Throwable {
+ Object ret) throws Throwable {
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
AbstractSpan span = ContextManager.activeSpan();
@@ -69,8 +63,9 @@ public class ControllerServiceMethodInterceptor implements InstanceMethodsAround
return ret;
}
- @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
- Class>[] argumentsTypes, Throwable t) {
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/RequestMappingMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/RequestMappingMethodInterceptor.java
new file mode 100644
index 000000000..b04942cb1
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/RequestMappingMethodInterceptor.java
@@ -0,0 +1,24 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+import java.lang.reflect.Method;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * The RequestMappingMethodInterceptor only use the first mapping value.
+ * it will inteceptor with @RequestMapping
+ * @author clevertension
+ */
+public class RequestMappingMethodInterceptor extends AbstractMethodInteceptor {
+ @Override
+ public String getRequestURL(Method method) {
+ String requestURL = "";
+ RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
+ if (methodRequestMapping.value().length > 0) {
+ requestURL = methodRequestMapping.value()[0];
+ } else if (methodRequestMapping.path().length > 0) {
+ requestURL = methodRequestMapping.path()[0];
+ }
+ return requestURL;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/RestMappingMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/RestMappingMethodInterceptor.java
new file mode 100644
index 000000000..ee69bde38
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/RestMappingMethodInterceptor.java
@@ -0,0 +1,56 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+import java.lang.reflect.Method;
+
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * The RestMappingMethodInterceptor only use the first mapping value.
+ * it will inteceptor with
+ * @GetMapping, @PostMapping, @PutMapping
+ * @DeleteMapping, @PatchMapping
+ * @author clevertension
+ */
+public class RestMappingMethodInterceptor extends AbstractMethodInteceptor {
+ @Override
+ public String getRequestURL(Method method) {
+ String requestURL = "";
+ GetMapping getMapping = method.getAnnotation(GetMapping.class);
+ PostMapping postMapping = method.getAnnotation(PostMapping.class);
+ PutMapping putMapping = method.getAnnotation(PutMapping.class);
+ DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
+ PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
+ if (getMapping != null) {
+ if (getMapping.value().length > 0) {
+ requestURL = getMapping.value()[0];
+ } else if (getMapping.path().length > 0) {
+ requestURL = getMapping.path()[0];
+ }
+ } else if (postMapping != null) {
+ if (postMapping.value().length > 0) {
+ requestURL = postMapping.value()[0];
+ } else if (postMapping.path().length > 0) {
+ requestURL = postMapping.path()[0];
+ }
+ } else if (putMapping != null) {
+ if (putMapping.value().length > 0) {
+ requestURL = putMapping.value()[0];
+ } else if (putMapping.path().length > 0) {
+ requestURL = putMapping.path()[0];
+ }
+ } else if (deleteMapping != null) {
+ if (deleteMapping.value().length > 0) {
+ requestURL = deleteMapping.value()[0];
+ } else if (deleteMapping.path().length > 0) {
+ requestURL = deleteMapping.path()[0];
+ }
+ } else if (patchMapping != null) {
+ if (patchMapping.value().length > 0) {
+ requestURL = patchMapping.value()[0];
+ } else if (patchMapping.path().length > 0) {
+ requestURL = patchMapping.path()[0];
+ }
+ }
+ return requestURL;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/AbstractControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/AbstractControllerInstrumentation.java
index 96f7715d7..feb6323a2 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/AbstractControllerInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/AbstractControllerInstrumentation.java
@@ -20,8 +20,8 @@ import static org.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.by
* org.skywalking.apm.plugin.spring.mvc.ControllerConstructorInterceptor set the controller base path to
* dynamic field before execute constructor.
*
- * org.skywalking.apm.plugin.spring.mvc.ControllerServiceMethodInterceptor get the request path from
- * dynamic field first, if not found, ControllerServiceMethodInterceptor generate request path that
+ * org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor get the request path from
+ * dynamic field first, if not found, RequestMappingMethodInterceptor generate request path that
* combine the path value of current annotation on current method and the base path and set the new path to the dynamic
* filed
*
@@ -56,7 +56,26 @@ public abstract class AbstractControllerInstrumentation extends ClassInstanceMet
@Override
public String getMethodsInterceptor() {
- return "org.skywalking.apm.plugin.spring.mvc.ControllerServiceMethodInterceptor";
+ return "org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor";
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return isAnnotatedWith(named("org.springframework.web.bind.annotation.GetMapping"))
+ .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PostMapping")))
+ .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PutMapping")))
+ .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.DeleteMapping")))
+ .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PatchMapping")));
+ }
+ @Override
+ public String getMethodsInterceptor() {
+ return "org.skywalking.apm.plugin.spring.mvc.RestMappingMethodInterceptor";
}
@Override
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/ControllerConstructorInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/ControllerConstructorInterceptorTest.java
new file mode 100644
index 000000000..365e252b1
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/ControllerConstructorInterceptorTest.java
@@ -0,0 +1,107 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.lang.reflect.Method;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class ControllerConstructorInterceptorTest {
+ private ControllerConstructorInterceptor controllerConstructorInterceptor;
+ private final MockEnhancedInstance1 inst1 = new MockEnhancedInstance1();
+ private final MockEnhancedInstance2 inst2 = new MockEnhancedInstance2();
+ private final MockEnhancedInstance3 inst3 = new MockEnhancedInstance3();
+ @Before
+ public void setUp() throws Exception {
+ controllerConstructorInterceptor = new ControllerConstructorInterceptor();
+ }
+
+ @Test
+ public void testOnConstruct_Accuracy1() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(inst1, null);
+ PathMappingCache cache = (PathMappingCache)inst1.getSkyWalkingDynamicField();
+ Assert.assertNotNull(cache);
+
+ Object obj = new Object();
+ Method m = obj.getClass().getMethods()[0];
+ cache.addPathMapping(m, "#toString");
+
+ Assert.assertEquals("the two value should be equal", cache.findPathMapping(m), "/test1#toString");
+ }
+
+ @Test
+ public void testOnConstruct_Accuracy2() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(inst2, null);
+ PathMappingCache cache = (PathMappingCache)inst2.getSkyWalkingDynamicField();
+ Assert.assertNotNull(cache);
+
+ Object obj = new Object();
+ Method m = obj.getClass().getMethods()[0];
+ cache.addPathMapping(m, "#toString");
+
+ Assert.assertEquals("the two value should be equal", cache.findPathMapping(m), "#toString");
+ }
+
+ @Test
+ public void testOnConstruct_Accuracy3() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(inst3, null);
+ PathMappingCache cache = (PathMappingCache)inst3.getSkyWalkingDynamicField();
+ Assert.assertNotNull(cache);
+
+ Object obj = new Object();
+ Method m = obj.getClass().getMethods()[0];
+ cache.addPathMapping(m, "#toString");
+
+ Assert.assertEquals("the two value should be equal", cache.findPathMapping(m), "/test3#toString");
+ }
+
+ @RequestMapping(value="/test1")
+ private class MockEnhancedInstance1 implements EnhancedInstance {
+ private Object value;
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return value;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.value = value;
+ }
+ }
+
+ private class MockEnhancedInstance2 implements EnhancedInstance {
+ private Object value;
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return value;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.value = value;
+ }
+ }
+
+ @RequestMapping(path="/test3")
+ private class MockEnhancedInstance3 implements EnhancedInstance {
+ private Object value;
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return value;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/PathMappingCacheTest.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/PathMappingCacheTest.java
new file mode 100644
index 000000000..e7dd987a5
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/PathMappingCacheTest.java
@@ -0,0 +1,34 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+
+import java.lang.reflect.Method;
+
+import static org.powermock.api.mockito.PowerMockito.whenNew;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class PathMappingCacheTest {
+ private PathMappingCache pathMappingCache;
+
+ @Before
+ public void setUp() throws Exception {
+ pathMappingCache = new PathMappingCache("org.skywalking.apm.plugin.spring.mvc");
+ }
+
+ @Test
+ public void testAddPathMapping1() throws Throwable {
+ Object obj = new Object();
+ Method m = obj.getClass().getMethods()[0];
+ pathMappingCache.addPathMapping(m, "#toString");
+
+ Assert.assertEquals("the two value should be equal", pathMappingCache.findPathMapping(m), "org.skywalking.apm.plugin.spring.mvc#toString");
+
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/RequestMappingMethodInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/RequestMappingMethodInterceptorTest.java
new file mode 100644
index 000000000..7fa10b10c
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/RequestMappingMethodInterceptorTest.java
@@ -0,0 +1,157 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.skywalking.apm.agent.core.context.trace.*;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.skywalking.apm.agent.test.helper.SegmentRefHelper;
+import org.skywalking.apm.agent.test.helper.SpanHelper;
+import org.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
+import static org.skywalking.apm.agent.test.tools.SpanAssert.*;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class RequestMappingMethodInterceptorTest {
+ private RequestMappingMethodInterceptor interceptor;
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+
+ private ServletRequestAttributes servletRequestAttributes;
+
+ @Mock
+ private HttpServletRequest request;
+
+ @Mock
+ private HttpServletResponse response;
+ @Mock
+ private MethodInterceptResult methodInterceptResult;
+
+ private Object[] arguments;
+ private Class[] argumentType;
+
+ private EnhancedInstance enhancedInstance;
+
+ private ControllerConstructorInterceptor controllerConstructorInterceptor;
+
+ @Before
+ public void setUp() throws Exception {
+ interceptor = new RequestMappingMethodInterceptor();
+ enhancedInstance = new MockEnhancedInstance1();
+ controllerConstructorInterceptor = new ControllerConstructorInterceptor();
+ servletRequestAttributes = new ServletRequestAttributes(request, response);
+
+ when(request.getScheme()).thenReturn("http");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(8080);
+ when(request.getRequestURI()).thenReturn("/test/testRequestURL");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/testRequestURL"));
+ when(response.getStatus()).thenReturn(200);
+
+ arguments = new Object[] {request, response};
+ argumentType = new Class[] {request.getClass(), response.getClass()};
+
+
+ }
+
+ @Test
+ public void testWithoutSerializedContextData() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RequestMappingClass1 mappingClass1 = new RequestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("testRequestURL");
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0));
+ }
+
+ @Test
+ public void testWithOccurException() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RequestMappingClass1 mappingClass1 = new RequestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("testRequestURL");
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.handleMethodException(enhancedInstance, m, arguments, argumentType, new RuntimeException());
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0));
+ List logDataEntities = SpanHelper.getLogs(spans.get(0));
+ assertThat(logDataEntities.size(), is(1));
+ assertException(logDataEntities.get(0), RuntimeException.class);
+ }
+
+ private void assertTraceSegmentRef(TraceSegmentRef ref) {
+ assertThat(SegmentRefHelper.getEntryApplicationInstanceId(ref), is(1));
+ assertThat(SegmentRefHelper.getSpanId(ref), is(3));
+ assertThat(SegmentRefHelper.getTraceSegmentId(ref).toString(), is("1.444.555"));
+ }
+
+ private void assertHttpSpan(AbstractTracingSpan span) {
+ assertThat(span.getOperationName(), is("/test/testRequestURL"));
+ assertComponent(span, ComponentsDefine.SPRING_MVC_ANNOTATION);
+ assertTag(span, 0, "http://localhost:8080/test/testRequestURL");
+ assertThat(span.isEntry(), is(true));
+ assertLayer(span, SpanLayer.HTTP);
+ }
+
+ @RequestMapping(value = "/test")
+ private class MockEnhancedInstance1 implements EnhancedInstance {
+ private Object value;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return value;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.value = value;
+ }
+ }
+
+ private class RequestMappingClass1 {
+ @RequestMapping("/testRequestURL")
+ public void testRequestURL() {
+
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/RestMappingMethodInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/RestMappingMethodInterceptorTest.java
new file mode 100644
index 000000000..21ded57d7
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/RestMappingMethodInterceptorTest.java
@@ -0,0 +1,277 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.skywalking.apm.agent.core.context.trace.*;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.skywalking.apm.agent.test.helper.SegmentRefHelper;
+import org.skywalking.apm.agent.test.helper.SpanHelper;
+import org.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
+import static org.skywalking.apm.agent.test.tools.SpanAssert.*;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class RestMappingMethodInterceptorTest {
+ private RestMappingMethodInterceptor interceptor;
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+
+ @Mock
+ private HttpServletRequest request;
+
+ @Mock
+ private HttpServletResponse response;
+ @Mock
+ private MethodInterceptResult methodInterceptResult;
+
+ private Object[] arguments;
+ private Class[] argumentType;
+
+ private EnhancedInstance enhancedInstance;
+
+ private ControllerConstructorInterceptor controllerConstructorInterceptor;
+
+ @Before
+ public void setUp() throws Exception {
+ interceptor = new RestMappingMethodInterceptor();
+ enhancedInstance = new RestMappingMethodInterceptorTest.MockEnhancedInstance1();
+ controllerConstructorInterceptor = new ControllerConstructorInterceptor();
+
+ when(request.getScheme()).thenReturn("http");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(8080);
+ when(response.getStatus()).thenReturn(200);
+
+ arguments = new Object[] {request, response};
+ argumentType = new Class[] {request.getClass(), response.getClass()};
+
+
+ }
+
+ @Test
+ public void testGetMapping() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RestMappingClass1 mappingClass1 = new RestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("getRequestURL");
+ when(request.getRequestURI()).thenReturn("/test/testRequestURL");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/getRequestURL"));
+ ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0), "/getRequestURL");
+ }
+
+ @Test
+ public void testPostMapping() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RestMappingClass1 mappingClass1 = new RestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("postRequestURL");
+ when(request.getRequestURI()).thenReturn("/test/testRequestURL");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/postRequestURL"));
+ ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0), "/postRequestURL");
+ }
+
+
+ @Test
+ public void testPutMapping() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RestMappingClass1 mappingClass1 = new RestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("putRequestURL");
+ when(request.getRequestURI()).thenReturn("/test/testRequestURL");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/putRequestURL"));
+ ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0), "/putRequestURL");
+ }
+
+ @Test
+ public void testDeleteMapping() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RestMappingClass1 mappingClass1 = new RestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("deleteRequestURL");
+ when(request.getRequestURI()).thenReturn("/test/testRequestURL");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/deleteRequestURL"));
+ ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0), "/deleteRequestURL");
+ }
+
+ @Test
+ public void testPatchMapping() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RestMappingClass1 mappingClass1 = new RestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("patchRequestURL");
+ when(request.getRequestURI()).thenReturn("/test/testRequestURL");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/patchRequestURL"));
+ ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0), "/patchRequestURL");
+ }
+
+ @Test
+ public void testDummy() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RestMappingClass1 mappingClass1 = new RestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("dummy");
+ when(request.getRequestURI()).thenReturn("/test");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test"));
+ ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0), "");
+ }
+
+ @Test
+ public void testWithOccurException() throws Throwable {
+ controllerConstructorInterceptor.onConstruct(enhancedInstance, null);
+ RestMappingClass1 mappingClass1 = new RestMappingClass1();
+ Method m = mappingClass1.getClass().getMethod("getRequestURL");
+ when(request.getRequestURI()).thenReturn("/test/testRequestURL");
+ when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/getRequestURL"));
+ ServletRequestAttributes servletRequestAttributes = new ServletRequestAttributes(request, response);
+ RequestContextHolder.setRequestAttributes(servletRequestAttributes);
+
+ interceptor.beforeMethod(enhancedInstance, m, arguments, argumentType, methodInterceptResult);
+ interceptor.handleMethodException(enhancedInstance, m, arguments, argumentType, new RuntimeException());
+ interceptor.afterMethod(enhancedInstance, m, arguments, argumentType, null);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+
+ assertHttpSpan(spans.get(0), "/getRequestURL");
+ List logDataEntities = SpanHelper.getLogs(spans.get(0));
+ assertThat(logDataEntities.size(), is(1));
+ assertException(logDataEntities.get(0), RuntimeException.class);
+ }
+
+ private void assertTraceSegmentRef(TraceSegmentRef ref) {
+ assertThat(SegmentRefHelper.getEntryApplicationInstanceId(ref), is(1));
+ assertThat(SegmentRefHelper.getSpanId(ref), is(3));
+ assertThat(SegmentRefHelper.getTraceSegmentId(ref).toString(), is("1.444.555"));
+ }
+
+ private void assertHttpSpan(AbstractTracingSpan span, String suffix) {
+ assertThat(span.getOperationName(), is("/test" + suffix));
+ assertComponent(span, ComponentsDefine.SPRING_MVC_ANNOTATION);
+ assertTag(span, 0, "http://localhost:8080/test" + suffix);
+ assertThat(span.isEntry(), is(true));
+ assertLayer(span, SpanLayer.HTTP);
+ }
+
+ @RequestMapping(value = "/test")
+ private class MockEnhancedInstance1 implements EnhancedInstance {
+ private Object value;
+
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return value;
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ this.value = value;
+ }
+ }
+
+ private class RestMappingClass1 {
+ @GetMapping("/getRequestURL")
+ public void getRequestURL() {
+
+ }
+ @PostMapping("/postRequestURL")
+ public void postRequestURL() {
+
+ }
+ @PutMapping("/putRequestURL")
+ public void putRequestURL() {
+
+ }
+ @DeleteMapping("/deleteRequestURL")
+ public void deleteRequestURL() {
+
+ }
+ @PatchMapping("/patchRequestURL")
+ public void patchRequestURL() {
+
+ }
+ public void dummy() {
+
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/define/ControllerInstrumentationTest.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/define/ControllerInstrumentationTest.java
new file mode 100644
index 000000000..198d359c2
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/define/ControllerInstrumentationTest.java
@@ -0,0 +1,62 @@
+package org.skywalking.apm.plugin.spring.mvc.define;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatchers;
+
+import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class ControllerInstrumentationTest {
+ private ControllerInstrumentation controllerInstrumentation;
+
+ @Before
+ public void setUp() throws Exception {
+ controllerInstrumentation = new ControllerInstrumentation();
+ }
+
+ @Test
+ public void testGetEnhanceAnnotations() throws Throwable {
+ Assert.assertArrayEquals(new String[] {ControllerInstrumentation.ENHANCE_ANNOTATION},
+ controllerInstrumentation.getEnhanceAnnotations());
+ }
+
+ @Test
+ public void testGetInstanceMethodsInterceptPoints() throws Throwable {
+ InstanceMethodsInterceptPoint[] methodPoints = controllerInstrumentation.getInstanceMethodsInterceptPoints();
+ assertThat(methodPoints.length, is(2));
+ assertThat(methodPoints[0].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor"));
+ assertThat(methodPoints[1].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RestMappingMethodInterceptor"));
+
+ Assert.assertFalse(methodPoints[0].isOverrideArgs());
+ Assert.assertFalse(methodPoints[1].isOverrideArgs());
+
+ Assert.assertNotNull(methodPoints[0].getMethodsMatcher());
+ Assert.assertNotNull(methodPoints[1].getMethodsMatcher());
+
+ }
+
+ @Test
+ public void testGetConstructorsInterceptPoints() throws Throwable {
+ ConstructorInterceptPoint[] cips = controllerInstrumentation.getConstructorsInterceptPoints();
+ Assert.assertEquals(cips.length, 1);
+ ConstructorInterceptPoint cip = cips[0];
+ Assert.assertNotNull(cip);
+
+ Assert.assertEquals(cip.getConstructorInterceptor(), "org.skywalking.apm.plugin.spring.mvc.ControllerConstructorInterceptor");
+ Assert.assertTrue(cip.getConstructorMatcher().equals(ElementMatchers.any()));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/define/RestControllerInstrumentationTest.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/define/RestControllerInstrumentationTest.java
new file mode 100644
index 000000000..f2b8d16df
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/skywalking/apm/plugin/spring/mvc/define/RestControllerInstrumentationTest.java
@@ -0,0 +1,45 @@
+package org.skywalking.apm.plugin.spring.mvc.define;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class RestControllerInstrumentationTest {
+ private RestControllerInstrumentation restControllerInstrumentation;
+
+ @Before
+ public void setUp() throws Exception {
+ restControllerInstrumentation = new RestControllerInstrumentation();
+ }
+
+ @Test
+ public void testGetEnhanceAnnotations() throws Throwable {
+ Assert.assertArrayEquals(new String[] {restControllerInstrumentation.ENHANCE_ANNOTATION},
+ restControllerInstrumentation.getEnhanceAnnotations());
+ }
+
+ @Test
+ public void testGetInstanceMethodsInterceptPoints() throws Throwable {
+ InstanceMethodsInterceptPoint[] methodPoints = restControllerInstrumentation.getInstanceMethodsInterceptPoints();
+ assertThat(methodPoints.length, is(2));
+ assertThat(methodPoints[0].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RequestMappingMethodInterceptor"));
+ assertThat(methodPoints[1].getMethodsInterceptor(), is("org.skywalking.apm.plugin.spring.mvc.RestMappingMethodInterceptor"));
+
+ Assert.assertFalse(methodPoints[0].isOverrideArgs());
+ Assert.assertFalse(methodPoints[1].isOverrideArgs());
+
+ Assert.assertNotNull(methodPoints[0].getMethodsMatcher());
+ Assert.assertNotNull(methodPoints[1].getMethodsMatcher());
+
+ }
+}