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.