diff --git a/skywalking-sniffer/skywalking-sdk-plugin/dubbo-plugin/src/main/java/com/a/eye/skywalking/plugin/dubbo/DubboInstrumentation.java b/skywalking-sniffer/skywalking-sdk-plugin/dubbo-plugin/src/main/java/com/a/eye/skywalking/plugin/dubbo/DubboInstrumentation.java index 2f65c34e1..0890dcdcc 100644 --- a/skywalking-sniffer/skywalking-sdk-plugin/dubbo-plugin/src/main/java/com/a/eye/skywalking/plugin/dubbo/DubboInstrumentation.java +++ b/skywalking-sniffer/skywalking-sdk-plugin/dubbo-plugin/src/main/java/com/a/eye/skywalking/plugin/dubbo/DubboInstrumentation.java @@ -12,9 +12,8 @@ import net.bytebuddy.matcher.ElementMatcher; import static net.bytebuddy.matcher.ElementMatchers.named; /** - * {@link DubboInstrumentation} present that skywalking use class {@link DubboInterceptor} to - * enhance class {@link com.alibaba.dubbo.monitor.support.MonitorFilter#invoke(Invoker, Invocation)} - * for support trace of the dubbo framework. + * {@link DubboInstrumentation} presents that skywalking use class {@link DubboInterceptor} to + * intercept {@link com.alibaba.dubbo.monitor.support.MonitorFilter#invoke(Invoker, Invocation)}. * * @author zhangxin */ diff --git a/skywalking-sniffer/skywalking-sdk-plugin/pom.xml b/skywalking-sniffer/skywalking-sdk-plugin/pom.xml index ee2399093..e1a61be3c 100644 --- a/skywalking-sniffer/skywalking-sdk-plugin/pom.xml +++ b/skywalking-sniffer/skywalking-sdk-plugin/pom.xml @@ -33,6 +33,12 @@ skywalking-api 3.0-2017 + + com.a.eye + skywalking-sniffer-mock + 3.0-2017 + test + diff --git a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/TomcatPluginInterceptor.java b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/TomcatPluginInterceptor.java deleted file mode 100644 index e46e1b6ab..000000000 --- a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/TomcatPluginInterceptor.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.a.eye.skywalking.api.plugin.tomcat78x; - -import com.a.eye.skywalking.api.Tracing; -import com.a.eye.skywalking.invoke.monitor.RPCServerInvokeMonitor; -import com.a.eye.skywalking.model.ContextData; -import com.a.eye.skywalking.model.Identification; -import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext; -import com.a.eye.skywalking.plugin.interceptor.enhance.ConstructorInvokeContext; -import com.a.eye.skywalking.plugin.interceptor.enhance.InstanceMethodInvokeContext; -import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; -import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class TomcatPluginInterceptor implements InstanceMethodsAroundInterceptor { - private final String secondKey = "ContextData"; - private String tracingName = DEFAULT_TRACE_NAME; - private static final String DEFAULT_TRACE_NAME = "SkyWalking-TRACING-NAME"; - private static final String TRACE_ID_HEADER_NAME = "SW-TraceId"; - - @Override - public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) { - Object[] args = interceptorContext.allArguments(); - HttpServletRequest requests = (HttpServletRequest) args[0]; - String tracingHeaderValue = requests.getHeader(tracingName); - ContextData contextData = null; - if (tracingHeaderValue != null) { - String contextDataStr = null; - int index = tracingHeaderValue.indexOf("="); - if (index > 0) { - String key = tracingHeaderValue.substring(0, index); - if (secondKey.equals(key)) { - contextDataStr = tracingHeaderValue.substring(index + 1); - } - } - - if (contextDataStr != null && contextDataStr.length() > 0) { - contextData = new ContextData(contextDataStr); - } - } - RPCServerInvokeMonitor rpcServerInvokeMonitor = new RPCServerInvokeMonitor(); - rpcServerInvokeMonitor.beforeInvoke(contextData, generateIdentification(requests)); - } - - - private Identification generateIdentification(HttpServletRequest request) { - return Identification.newBuilder() - .viewPoint(request.getRequestURL().toString()) - .spanType(WebBuriedPointType.INSTANCE) - .build(); - } - - - @Override - public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) { - Object[] args = interceptorContext.allArguments(); - HttpServletResponse httpServletResponse = (HttpServletResponse) args[1]; - httpServletResponse.addHeader(TRACE_ID_HEADER_NAME, Tracing.getTraceId()); - new RPCServerInvokeMonitor().afterInvoke(); - return ret; - } - - @Override - public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, - InstanceMethodInvokeContext interceptorContext) { - new RPCServerInvokeMonitor().occurException(t); - } - -} diff --git a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/WebBuriedPointType.java b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/WebBuriedPointType.java deleted file mode 100644 index d353c784a..000000000 --- a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/WebBuriedPointType.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.a.eye.skywalking.api.plugin.tomcat78x; - -import com.a.eye.skywalking.api.IBuriedPointType; - -public enum WebBuriedPointType implements IBuriedPointType { - INSTANCE; - - @Override - public String getTypeName() { - return "W"; - } - - @Override - public CallType getCallType() { - return CallType.SYNC; - } - -} diff --git a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/define/TomcatPluginDefine.java b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/define/TomcatPluginDefine.java deleted file mode 100644 index d79b185c9..000000000 --- a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/api/plugin/tomcat78x/define/TomcatPluginDefine.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.a.eye.skywalking.api.plugin.tomcat78x.define; - -import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint; -import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint; -import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.matcher.ElementMatcher; - -import static net.bytebuddy.matcher.ElementMatchers.named; - -public class TomcatPluginDefine extends ClassInstanceMethodsEnhancePluginDefine { - @Override - protected String enhanceClassName() { - return "org.apache.catalina.core.StandardEngineValve"; - } - - @Override - protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { - return null; - } - - @Override - protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { - return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() { - @Override - public ElementMatcher getMethodsMatcher() { - return named("invoke"); - } - - @Override - public String getMethodsInterceptor() { - return "com.a.eye.skywalking.plugin.tomcat78x.TomcatPluginInterceptor"; - } - }}; - } -} diff --git a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/plugin/tomcat78x/TomcatInterceptor.java b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/plugin/tomcat78x/TomcatInterceptor.java new file mode 100644 index 000000000..ef9421ea6 --- /dev/null +++ b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/plugin/tomcat78x/TomcatInterceptor.java @@ -0,0 +1,68 @@ +package com.a.eye.skywalking.plugin.tomcat78x; + +import com.a.eye.skywalking.api.context.ContextCarrier; +import com.a.eye.skywalking.api.context.ContextManager; +import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext; +import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext; +import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult; +import com.a.eye.skywalking.api.util.StringUtil; +import com.a.eye.skywalking.trace.Span; +import com.a.eye.skywalking.trace.tag.Tags; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * {@link TomcatInterceptor} fetch the serialized context data by use {@link HttpServletRequest#getHeader(String)}. + * The {@link com.a.eye.skywalking.trace.TraceSegment#primaryRef} of current trace segment will reference to the trace segment id + * of the previous level if the serialized context is not null. + */ +public class TomcatInterceptor implements InstanceMethodsAroundInterceptor { + public static final String HEADER_NAME_OF_CONTEXT_DATA = "SKYWALKING_CONTEXT_DATA"; + public static final String TOMCAT_COMPONENT = "Tomcat"; + + /** + * The {@link com.a.eye.skywalking.trace.TraceSegment#primaryRef} of current trace segment will reference to the trace segment id + * of the previous level if the serialized context is not null. + * + * @param context instance context, a class instance only has one {@link EnhancedClassInstanceContext} instance. + * @param interceptorContext method context, includes class name, method name, etc. + * @param result change this result, if you want to truncate the method. + */ + @Override + public void beforeMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, MethodInterceptResult result) { + Object[] args = interceptorContext.allArguments(); + HttpServletRequest request = (HttpServletRequest) args[0]; + + Span span = ContextManager.INSTANCE.createSpan(request.getRequestURI()); + Tags.COMPONENT.set(span, TOMCAT_COMPONENT); + Tags.URL.set(span, request.getRequestURL().toString()); + Tags.SPAN_LAYER.asHttp(span); + + String tracingHeaderValue = request.getHeader(HEADER_NAME_OF_CONTEXT_DATA); + if (!StringUtil.isEmpty(tracingHeaderValue)) { + ContextManager.INSTANCE.extract(new ContextCarrier().deserialize(tracingHeaderValue)); + } + } + + @Override + public Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret) { + HttpServletResponse response = (HttpServletResponse) interceptorContext.allArguments()[1]; + + Span span = ContextManager.INSTANCE.activeSpan(); + Tags.STATUS_CODE.set(span, response.getStatus()); + ContextManager.INSTANCE.stopSpan(); + + return ret; + } + + @Override + public void handleMethodException(Throwable t, EnhancedClassInstanceContext context, + InstanceMethodInvokeContext interceptorContext) { + Span span = ContextManager.INSTANCE.activeSpan(); + span.log(t); + Tags.ERROR.set(span, true); + } + +} diff --git a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/plugin/tomcat78x/define/TomcatInstrumentation.java b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/plugin/tomcat78x/define/TomcatInstrumentation.java new file mode 100644 index 000000000..c512d84ff --- /dev/null +++ b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/com/a/eye/skywalking/plugin/tomcat78x/define/TomcatInstrumentation.java @@ -0,0 +1,52 @@ +package com.a.eye.skywalking.plugin.tomcat78x.define; + +import com.a.eye.skywalking.api.plugin.interceptor.ConstructorInterceptPoint; +import com.a.eye.skywalking.api.plugin.interceptor.InstanceMethodsInterceptPoint; +import com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import com.a.eye.skywalking.plugin.tomcat78x.TomcatInterceptor; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * {@link TomcatInstrumentation} presents that skywalking use class {@link TomcatInterceptor} to + * intercept {@link org.apache.catalina.core.StandardEngineValve#invoke(Request, Response)}. + * + * @author zhangxin + */ +public class TomcatInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_CLASS = "org.apache.catalina.core.StandardEngineValve"; + + private static final String INTERCEPT_CLASS = "com.a.eye.skywalking.plugin.tomcat78x.TomcatInterceptor"; + + @Override + protected String enhanceClassName() { + return ENHANCE_CLASS; + } + + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return null; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named("invoke"); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } + }}; + } +} diff --git a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def index 9433b13c2..b98f1ae95 100644 --- a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def +++ b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def @@ -1 +1 @@ -com.a.eye.skywalking.plugin.tomcat78x.define.TomcatPluginDefine +com.a.eye.skywalking.plugin.tomcat78x.define.TomcatInstrumentation diff --git a/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/java/com/a/eye/skywalking/plugin/tomcat78x/TomcatInterceptorTest.java b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/java/com/a/eye/skywalking/plugin/tomcat78x/TomcatInterceptorTest.java new file mode 100644 index 000000000..fbe643dda --- /dev/null +++ b/skywalking-sniffer/skywalking-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/java/com/a/eye/skywalking/plugin/tomcat78x/TomcatInterceptorTest.java @@ -0,0 +1,140 @@ +package com.a.eye.skywalking.plugin.tomcat78x; + +import com.a.eye.skywalking.api.context.TracerContext; +import com.a.eye.skywalking.api.plugin.interceptor.EnhancedClassInstanceContext; +import com.a.eye.skywalking.api.plugin.interceptor.enhance.InstanceMethodInvokeContext; +import com.a.eye.skywalking.api.plugin.interceptor.enhance.MethodInterceptResult; +import com.a.eye.skywalking.sniffer.mock.context.MockTracerContextListener; +import com.a.eye.skywalking.sniffer.mock.context.SegmentAssert; +import com.a.eye.skywalking.trace.LogData; +import com.a.eye.skywalking.trace.Span; +import com.a.eye.skywalking.trace.TraceSegment; +import com.a.eye.skywalking.trace.TraceSegmentRef; +import com.a.eye.skywalking.trace.tag.Tags; + +import org.hamcrest.CoreMatchers; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class TomcatInterceptorTest { + + private TomcatInterceptor tomcatInterceptor; + private MockTracerContextListener contextListener; + + @Mock + private HttpServletRequest request; + @Mock + private HttpServletResponse response; + @Mock + private EnhancedClassInstanceContext classInstanceContext; + @Mock + private InstanceMethodInvokeContext methodInvokeContext; + @Mock + private MethodInterceptResult methodInterceptResult; + + @Before + public void setUp() throws Exception { + tomcatInterceptor = new TomcatInterceptor(); + contextListener = new MockTracerContextListener(); + + TracerContext.ListenerManager.add(contextListener); + + when(request.getRequestURI()).thenReturn("/test/testRequestURL"); + when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/testRequestURL")); + when(response.getStatus()).thenReturn(200); + when(methodInvokeContext.allArguments()).thenReturn(new Object[]{request, response}); + } + + @Test + public void testWithoutSerializedContextData() { + tomcatInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult); + tomcatInterceptor.afterMethod(classInstanceContext, methodInvokeContext, null); + + contextListener.assertSize(1); + contextListener.assertTraceSegment(0, new SegmentAssert() { + @Override + public void call(TraceSegment traceSegment) { + assertThat(traceSegment.getSpans().size(), is(1)); + Span span = traceSegment.getSpans().get(0); + assertHttpSpan(span); + } + }); + } + + @Test + public void testWithSerializedContextData() { + when(request.getHeader(TomcatInterceptor.HEADER_NAME_OF_CONTEXT_DATA)).thenReturn("302017.1487666919810.624424584.17332.1.1|1"); + + tomcatInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult); + tomcatInterceptor.afterMethod(classInstanceContext, methodInvokeContext, null); + + contextListener.assertSize(1); + contextListener.assertTraceSegment(0, new SegmentAssert() { + @Override + public void call(TraceSegment traceSegment) { + assertThat(traceSegment.getSpans().size(), is(1)); + Span span = traceSegment.getSpans().get(0); + assertHttpSpan(span); + assertTraceSegmentRef(traceSegment.getPrimaryRef()); + } + }); + } + + @Test + public void testWithOccurException(){ + tomcatInterceptor.beforeMethod(classInstanceContext, methodInvokeContext, methodInterceptResult); + tomcatInterceptor.handleMethodException(new RuntimeException(), classInstanceContext, methodInvokeContext); + tomcatInterceptor.afterMethod(classInstanceContext, methodInvokeContext, null); + + contextListener.assertSize(1); + contextListener.assertTraceSegment(0, new SegmentAssert() { + @Override + public void call(TraceSegment traceSegment) { + assertThat(traceSegment.getSpans().size(), is(1)); + Span span = traceSegment.getSpans().get(0); + assertHttpSpan(span); + assertThat(span.getLogs().size(), is(1)); + assertSpanLog(span.getLogs().get(0)); + } + }); + } + + private void assertSpanLog(LogData logData) { + assertThat(logData.getFields().size(), is(3)); + assertThat(logData.getFields().get("error.kind"), CoreMatchers.is(RuntimeException.class.getName())); + assertNull(logData.getFields().get("message")); + } + + private void assertTraceSegmentRef(TraceSegmentRef ref) { + assertThat(ref.getSpanId(), is(1)); + assertThat(ref.getTraceSegmentId(), is("302017.1487666919810.624424584.17332.1.1")); + } + + private void assertHttpSpan(Span span) { + assertThat(span.getOperationName(), is("/test/testRequestURL")); + assertThat(Tags.COMPONENT.get(span), is("Tomcat")); + assertThat(Tags.URL.get(span), is("http://localhost:8080/test/testRequestURL")); + assertThat(Tags.STATUS_CODE.get(span), is(200)); + assertTrue(Tags.SPAN_LAYER.isHttp(span)); + } + + @After + public void tearDown() throws Exception { + TracerContext.ListenerManager.remove(new MockTracerContextListener()); + } + +} \ No newline at end of file