diff --git a/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java index 80affad29..5c9b7c0ef 100644 --- a/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java +++ b/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java @@ -35,7 +35,11 @@ public class ComponentsDefine { public static final OfficialComponent SPRING_MVC_ANNOTATION = new OfficialComponent(14, "SpringMVC"); - public static final OfficialComponent STRUTS2 = new OfficialComponent(14, "Struts2"); + public static final OfficialComponent STRUTS2 = new OfficialComponent(15, "Struts2"); + + public static final OfficialComponent NUTZ_MVC_ANNOTATION = new OfficialComponent(16, "NutzMVC"); + + public static final OfficialComponent NUTZ_HTTP = new OfficialComponent(17, "NutzHttp"); private static ComponentsDefine instance = new ComponentsDefine(); @@ -46,7 +50,7 @@ public class ComponentsDefine { } public ComponentsDefine() { - components = new String[16]; + components = new String[18]; addComponent(TOMCAT); addComponent(HTTPCLIENT); addComponent(DUBBO); @@ -62,6 +66,8 @@ public class ComponentsDefine { addComponent(SPRING_REST_TEMPLATE); addComponent(SPRING_MVC_ANNOTATION); addComponent(STRUTS2); + addComponent(NUTZ_MVC_ANNOTATION); + addComponent(NUTZ_HTTP); } private void addComponent(OfficialComponent component) { diff --git a/apm-sniffer/apm-agent/pom.xml b/apm-sniffer/apm-agent/pom.xml index 53ea8e30c..0aa99ea71 100644 --- a/apm-sniffer/apm-agent/pom.xml +++ b/apm-sniffer/apm-agent/pom.xml @@ -105,6 +105,16 @@ apm-struts2-2.x-plugin ${project.version} + + org.skywalking + apm-nutz-mvc-annotation-1.x-plugin + ${project.version} + + + org.skywalking + apm-nutz-http-1.x-plugin + ${project.version} + diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/pom.xml new file mode 100644 index 000000000..defd73beb --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/pom.xml @@ -0,0 +1,24 @@ + + + nutz-plugins + org.skywalking + 3.2.1-2017 + + 4.0.0 + + apm-nutz-http-1.x-plugin + jar + + http-1.x-plugin + http://maven.apache.org + + + + org.nutz + nutz + 1.r.62 + provided + + + diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/SenderConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/SenderConstructorInterceptor.java new file mode 100644 index 000000000..640b6e822 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/SenderConstructorInterceptor.java @@ -0,0 +1,12 @@ +package org.skywalking.apm.plugin.nutz.http.sync; + +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +public class SenderConstructorInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(final EnhancedInstance objInst, final Object[] allArguments) { + objInst.setSkyWalkingDynamicField(allArguments[0]); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/SenderSendInterceptor.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/SenderSendInterceptor.java new file mode 100644 index 000000000..b7326ad31 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/SenderSendInterceptor.java @@ -0,0 +1,63 @@ +package org.skywalking.apm.plugin.nutz.http.sync; + +import java.lang.reflect.Method; +import java.net.URI; + +import org.nutz.http.Request; +import org.nutz.http.Request.METHOD; +import org.nutz.http.Response; +import org.skywalking.apm.agent.core.context.CarrierItem; +import org.skywalking.apm.agent.core.context.ContextCarrier; +import org.skywalking.apm.agent.core.context.ContextManager; +import org.skywalking.apm.agent.core.context.tag.Tags; +import org.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.skywalking.apm.agent.core.context.trace.SpanLayer; +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; + +public class SenderSendInterceptor implements InstanceMethodsAroundInterceptor { + + @Override + public void beforeMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments, final Class[] argumentsTypes, + final MethodInterceptResult result) throws Throwable { + Request req = (Request) objInst.getSkyWalkingDynamicField(); + final URI requestURL = req.getUrl().toURI(); + final METHOD httpMethod = req.getMethod(); + final ContextCarrier contextCarrier = new ContextCarrier(); + String remotePeer = requestURL.getHost() + ":" + requestURL.getPort(); + AbstractSpan span = ContextManager.createExitSpan(requestURL.getPath(), contextCarrier, remotePeer); + + span.setComponent(ComponentsDefine.NUTZ_HTTP); + Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath()); + Tags.HTTP.METHOD.set(span, httpMethod.toString()); + SpanLayer.asHttp(span); + + CarrierItem next = contextCarrier.items(); + while (next.hasNext()) { + next = next.next(); + req.getHeader().set(next.getHeadKey(), next.getHeadValue()); + } + } + + @Override + public Object afterMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments, final Class[] argumentsTypes, + Object ret) throws Throwable { + Response response = (Response)ret; + int statusCode = response.getStatus(); + AbstractSpan span = ContextManager.activeSpan(); + if (statusCode >= 400) { + span.errorOccurred(); + Tags.STATUS_CODE.set(span, Integer.toString(statusCode)); + } + ContextManager.stopSpan(); + return ret; + } + + @Override + public void handleMethodException(final EnhancedInstance objInst, final Method method, final Object[] allArguments, + final Class[] argumentsTypes, final Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/AbstractNutzHttpInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/AbstractNutzHttpInstrumentation.java new file mode 100644 index 000000000..e4b372866 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/AbstractNutzHttpInstrumentation.java @@ -0,0 +1,60 @@ +package org.skywalking.apm.plugin.nutz.http.sync.define; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +public abstract class AbstractNutzHttpInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String DO_SEND_METHOD_NAME = "send"; + private static final String DO_SEND_INTERCEPTOR = "org.skywalking.apm.plugin.nutz.http.sync.SenderSendInterceptor"; + private static final String DO_CONSTRUCTOR_INTERCEPTOR = "org.skywalking.apm.plugin.nutz.http.sync.SenderConstructorInterceptor"; + + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[]{ + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return ElementMatchers.takesArguments(1); + } + + @Override + public String getConstructorInterceptor() { + return DO_CONSTRUCTOR_INTERCEPTOR; + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(DO_SEND_METHOD_NAME); + } + + @Override + public String getMethodsInterceptor() { + return DO_SEND_INTERCEPTOR; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + protected abstract ClassMatch enhanceClass(); +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpFilePostSenderInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpFilePostSenderInstrumentation.java new file mode 100644 index 000000000..9082a9e57 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpFilePostSenderInstrumentation.java @@ -0,0 +1,11 @@ +package org.skywalking.apm.plugin.nutz.http.sync.define; + +import org.skywalking.apm.agent.core.plugin.match.ClassMatch; +import org.skywalking.apm.agent.core.plugin.match.NameMatch; + +public class NutzHttpFilePostSenderInstrumentation extends AbstractNutzHttpInstrumentation { + + protected ClassMatch enhanceClass() { + return NameMatch.byName("org.nutz.http.sender.FilePostSender"); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpGetSenderInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpGetSenderInstrumentation.java new file mode 100644 index 000000000..28bf2a1a6 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpGetSenderInstrumentation.java @@ -0,0 +1,12 @@ +package org.skywalking.apm.plugin.nutz.http.sync.define; + +import org.skywalking.apm.agent.core.plugin.match.ClassMatch; +import org.skywalking.apm.agent.core.plugin.match.NameMatch; + +public class NutzHttpGetSenderInstrumentation extends AbstractNutzHttpInstrumentation { + + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName("org.nutz.http.sender.GetSender"); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpPostSenderInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpPostSenderInstrumentation.java new file mode 100644 index 000000000..f1ed889f0 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/http/sync/define/NutzHttpPostSenderInstrumentation.java @@ -0,0 +1,13 @@ +package org.skywalking.apm.plugin.nutz.http.sync.define; + +import org.skywalking.apm.agent.core.plugin.match.ClassMatch; +import org.skywalking.apm.agent.core.plugin.match.NameMatch; + + +public class NutzHttpPostSenderInstrumentation extends AbstractNutzHttpInstrumentation { + + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName("org.nutz.http.sender.PostSender"); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 000000000..203a31f4d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,3 @@ +nutz-http-1.x=org.skywalking.apm.plugin.nutz.http.sync.define.NutzHttpGetSenderInstrumentation +nutz-http-1.x=org.skywalking.apm.plugin.nutz.http.sync.define.NutzHttpPostSenderInstrumentation +nutz-http-1.x=org.skywalking.apm.plugin.nutz.http.sync.define.NutzHttpFilePostSenderInstrumentation diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/test/java/org/skywalking/apm/plugin/nutz/http/sync/SenderInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/test/java/org/skywalking/apm/plugin/nutz/http/sync/SenderInterceptorTest.java new file mode 100644 index 000000000..61bc40f1d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/http-1.x-plugin/src/test/java/org/skywalking/apm/plugin/nutz/http/sync/SenderInterceptorTest.java @@ -0,0 +1,114 @@ +package org.skywalking.apm.plugin.nutz.http.sync; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.nutz.http.Request; +import org.nutz.http.Request.METHOD; +import org.nutz.http.Response; +import org.nutz.http.Sender; +import org.nutz.http.sender.FilePostSender; +import org.nutz.http.sender.GetSender; +import org.nutz.http.sender.PostSender; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; +import org.skywalking.apm.agent.core.boot.ServiceManager; +import org.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +import org.skywalking.apm.agent.core.context.trace.TraceSegment; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.test.helper.SegmentHelper; +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; + +@RunWith(org.powermock.modules.junit4.PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class SenderInterceptorTest { + + @SegmentStoragePoint + public SegmentStorage segmentStorage; + + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + + @Mock + private EnhancedInstance enhancedInstance; + + @Mock + Response resp; + + SenderConstructorInterceptor constructorInterceptPoint; + + SenderSendInterceptor senderSendInterceptor; + + Method sendMethod; + Object[] allArguments; + Class[] argumentsTypes; + + @Before + public void setUp() throws Exception { + ServiceManager.INSTANCE.boot(); + constructorInterceptPoint = new SenderConstructorInterceptor(); + senderSendInterceptor = new SenderSendInterceptor(); + } + + public void setupSender(Class klass) throws NoSuchMethodException, SecurityException { + sendMethod = klass.getMethod("send"); + allArguments = new Object[0]; + argumentsTypes = new Class[0]; + } + + @Test + public void test_constructor() { + Request request = Request.create("https://nutz.cn/yvr/list", METHOD.GET); + constructorInterceptPoint.onConstruct(enhancedInstance, new Object[]{request}); + verify(enhancedInstance, times(1)).setSkyWalkingDynamicField(request); + } + + @Test + public void test_getsender_send() throws NoSuchMethodException, SecurityException, Throwable { + setupSender(GetSender.class); + _sender_sender_test(); + } + + @Test + public void test_postsender_send() throws NoSuchMethodException, SecurityException, Throwable { + setupSender(PostSender.class); + _sender_sender_test(); + } + + @Test + public void test_filepostsender_send() throws NoSuchMethodException, SecurityException, Throwable { + setupSender(FilePostSender.class); + _sender_sender_test(); + } + + protected void _sender_sender_test() throws Throwable { + Request request = Request.create("https://nutz.cn/yvr/list", METHOD.GET); + constructorInterceptPoint.onConstruct(enhancedInstance, new Object[]{request}); + verify(enhancedInstance, times(1)).setSkyWalkingDynamicField(request); + + when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn(request); + when(resp.getStatus()).thenReturn(200); + + senderSendInterceptor.beforeMethod(enhancedInstance, sendMethod, allArguments, argumentsTypes, null); + senderSendInterceptor.afterMethod(enhancedInstance, sendMethod, allArguments, argumentsTypes, resp); + + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertThat(spans.size(), is(1)); + assertThat(spans.get(0).getOperationName(), is("/yvr/list")); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/pom.xml new file mode 100644 index 000000000..b71d4f8ac --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/pom.xml @@ -0,0 +1,30 @@ + + + nutz-plugins + org.skywalking + 3.2.1-2017 + + 4.0.0 + + apm-nutz-mvc-annotation-1.x-plugin + jar + + mvc-annotation-1.x-plugin + http://maven.apache.org + + + + org.nutz + nutz + 1.r.62 + provided + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/ActionConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/ActionConstructorInterceptor.java new file mode 100644 index 000000000..930e041de --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/ActionConstructorInterceptor.java @@ -0,0 +1,23 @@ +package org.skywalking.apm.plugin.nutz.mvc; + +import org.nutz.mvc.annotation.At; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +/** + * + * @author wendal + */ +public class ActionConstructorInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + String basePath = ""; + At basePathRequestMapping = objInst.getClass().getAnnotation(At.class); + if (basePathRequestMapping != null) { + basePath = basePathRequestMapping.value()[0]; + } + PathMappingCache pathMappingCache = new PathMappingCache(basePath); + objInst.setSkyWalkingDynamicField(pathMappingCache); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/ActionMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/ActionMethodInterceptor.java new file mode 100644 index 000000000..ab96e057a --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/ActionMethodInterceptor.java @@ -0,0 +1,76 @@ +package org.skywalking.apm.plugin.nutz.mvc; + +import java.lang.reflect.Method; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.nutz.mvc.Mvcs; +import org.nutz.mvc.annotation.At; +import org.skywalking.apm.agent.core.context.CarrierItem; +import org.skywalking.apm.agent.core.context.ContextCarrier; +import org.skywalking.apm.agent.core.context.ContextManager; +import org.skywalking.apm.agent.core.context.tag.Tags; +import org.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.skywalking.apm.agent.core.context.trace.SpanLayer; +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; + +/** + * The ActionMethodInterceptor only use the first mapping value. + * + * @See {@link ActionConstructorInterceptor} to explain why we are doing this. + * @author wendal + */ +public class ActionMethodInterceptor implements InstanceMethodsAroundInterceptor { + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + PathMappingCache pathMappingCache = (PathMappingCache)objInst.getSkyWalkingDynamicField(); + String requestURL = pathMappingCache.findPathMapping(method); + if (requestURL == null) { + At methodRequestMapping = method.getAnnotation(At.class); + if (methodRequestMapping.value().length > 0) { + requestURL = methodRequestMapping.value()[0]; + } else { + requestURL = ""; + } + pathMappingCache.addPathMapping(method, requestURL); + requestURL = pathMappingCache.findPathMapping(method); + } + + HttpServletRequest request = Mvcs.getReq(); + ContextCarrier contextCarrier = new ContextCarrier(); + CarrierItem next = contextCarrier.items(); + while (next.hasNext()) { + next = next.next(); + next.setHeadValue(request.getHeader(next.getHeadKey())); + } + AbstractSpan span = ContextManager.createEntrySpan(requestURL, contextCarrier); + Tags.URL.set(span, request.getRequestURL().toString()); + Tags.HTTP.METHOD.set(span, request.getMethod()); + span.setComponent(ComponentsDefine.NUTZ_MVC_ANNOTATION); + SpanLayer.asHttp(span); + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret) throws Throwable { + HttpServletResponse response = Mvcs.getResp(); + + AbstractSpan span = ContextManager.activeSpan(); + if (response.getStatus() >= 400) { + span.errorOccurred(); + Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus())); + } + ContextManager.stopSpan(); + return ret; + } + + @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/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/PathMappingCache.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/PathMappingCache.java new file mode 100644 index 000000000..7df1b31ba --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/PathMappingCache.java @@ -0,0 +1,29 @@ +package org.skywalking.apm.plugin.nutz.mvc; + +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; + +/** + * The PathMappingCache represents a mapping cache. + * key: {@link Method} + * value: the url pattern + * + * @author wendal + */ +public class PathMappingCache { + private String classPath = ""; + + private ConcurrentHashMap methodPathMapping = new ConcurrentHashMap(); + + public PathMappingCache(String classPath) { + this.classPath = classPath; + } + + public String findPathMapping(Method method) { + return methodPathMapping.get(method); + } + + public void addPathMapping(Method method, String methodPath) { + methodPathMapping.put(method, classPath + methodPath); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/define/ActionInstrumentation.java b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/define/ActionInstrumentation.java new file mode 100644 index 000000000..406789852 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/java/org/skywalking/apm/plugin/nutz/mvc/define/ActionInstrumentation.java @@ -0,0 +1,67 @@ +package org.skywalking.apm.plugin.nutz.mvc.define; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch; + +import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class ActionInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + public static final String ENHANCE_ANNOTATION = "org.nutz.mvc.annotation.At"; + + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return "org.skywalking.apm.plugin.nutz.mvc.ActionConstructorInterceptor"; + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return isAnnotatedWith(named("org.nutz.mvc.annotation.At")); + } + + @Override + public String getMethodsInterceptor() { + return "org.skywalking.apm.plugin.nutz.mvc.ActionMethodInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return byClassAnnotationMatch(getEnhanceAnnotations()); + } + + protected String[] getEnhanceAnnotations() { + return new String[] {ENHANCE_ANNOTATION}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 000000000..c6566dcf3 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/mvc-annotation-1.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1 @@ +nutz-mvc-annotation-1.x=org.skywalking.apm.plugin.nutz.mvc.define.ActionInstrumentation \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/nutz-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/nutz-plugins/pom.xml new file mode 100644 index 000000000..06b11ae04 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/nutz-plugins/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + + org.skywalking + apm-sdk-plugin + 3.2.1-2017 + + + nutz-plugins + + + http-1.x-plugin + mvc-annotation-1.x-plugin + + pom + + apm-sdk-plugin + http://maven.apache.org + + + UTF-8 + + + diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index 54bfee03c..33ce19e05 100644 --- a/apm-sniffer/apm-sdk-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/pom.xml @@ -24,6 +24,7 @@ resin-4.x-plugin spring-plugins struts2-2.x-plugin + nutz-plugins pom