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 912efa40c..86a684b59 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
@@ -31,6 +31,10 @@ public class ComponentsDefine {
public static final OfficialComponent OKHTTP = new OfficialComponent(12, "OKHttp");
+ public static final OfficialComponent SPRING_REST_TEMPLATE = new OfficialComponent(13, "SpringRestTemplate");
+
+ public static final OfficialComponent SPRING_MVC_ANNOTATION = new OfficialComponent(14, "SpringMVCAnnotation");
+
private static ComponentsDefine instance = new ComponentsDefine();
private String[] components;
@@ -40,7 +44,7 @@ public class ComponentsDefine {
}
public ComponentsDefine() {
- components = new String[13];
+ components = new String[15];
addComponent(TOMCAT);
addComponent(HTTPCLIENT);
addComponent(DUBBO);
@@ -53,6 +57,8 @@ public class ComponentsDefine {
addComponent(RESIN);
addComponent(FEIGN);
addComponent(OKHTTP);
+ addComponent(SPRING_REST_TEMPLATE);
+ addComponent(SPRING_MVC_ANNOTATION);
}
private void addComponent(OfficialComponent component) {
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java
index 10efeb9b4..c6a8f9622 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/TracingContext.java
@@ -290,19 +290,19 @@ public class TracingContext implements AbstractTracerContext {
.find(remotePeer).doInCondition(
new PossibleFound.FoundAndObtain() {
@Override
- public Object doProcess(final int applicationId) {
+ public Object doProcess(final int peerId) {
return DictionaryManager.findOperationNameCodeSection()
- .findOrPrepare4Register(applicationId, operationName)
+ .findOnly(segment.getApplicationId(), operationName)
.doInCondition(
new PossibleFound.FoundAndObtain() {
@Override
public Object doProcess(int operationId) {
- return new ExitSpan(spanIdGenerator++, parentSpanId, operationId, applicationId);
+ return new ExitSpan(spanIdGenerator++, parentSpanId, operationId, peerId);
}
}, new PossibleFound.NotFoundAndObtain() {
@Override
public Object doProcess() {
- return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer);
+ return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, peerId);
}
});
}
@@ -310,7 +310,20 @@ public class TracingContext implements AbstractTracerContext {
new PossibleFound.NotFoundAndObtain() {
@Override
public Object doProcess() {
- return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer);
+ return DictionaryManager.findOperationNameCodeSection()
+ .findOnly(segment.getApplicationId(), operationName)
+ .doInCondition(
+ new PossibleFound.FoundAndObtain() {
+ @Override
+ public Object doProcess(int operationId) {
+ return new ExitSpan(spanIdGenerator++, parentSpanId, operationId, remotePeer);
+ }
+ }, new PossibleFound.NotFoundAndObtain() {
+ @Override
+ public Object doProcess() {
+ return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer);
+ }
+ });
}
});
push(exitSpan);
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java
index 4b2d69cfc..13ebe887e 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/EntrySpan.java
@@ -1,8 +1,6 @@
package org.skywalking.apm.agent.core.context.trace;
-import org.skywalking.apm.agent.core.dictionary.DictionaryManager;
import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
-import org.skywalking.apm.agent.core.dictionary.PossibleFound;
import org.skywalking.apm.network.trace.component.Component;
/**
@@ -18,19 +16,16 @@ import org.skywalking.apm.network.trace.component.Component;
*
* @author wusheng
*/
-public class EntrySpan extends AbstractTracingSpan {
- private int stackDepth;
+public class EntrySpan extends StackBasedTracingSpan {
private int currentMaxDepth;
public EntrySpan(int spanId, int parentSpanId, String operationName) {
super(spanId, parentSpanId, operationName);
- this.stackDepth = 0;
this.currentMaxDepth = 0;
}
public EntrySpan(int spanId, int parentSpanId, int operationId) {
super(spanId, parentSpanId, operationId);
- this.stackDepth = 0;
this.currentMaxDepth = 0;
}
@@ -81,31 +76,6 @@ public class EntrySpan extends AbstractTracingSpan {
}
}
- @Override
- public boolean finish(TraceSegment owner) {
- if (--stackDepth == 0) {
- if (this.operationId == DictionaryUtil.nullValue()) {
- this.operationId = (Integer)DictionaryManager.findOperationNameCodeSection()
- .findOrPrepare4Register(owner.getApplicationId(), operationName)
- .doInCondition(
- new PossibleFound.FoundAndObtain() {
- @Override public Object doProcess(int value) {
- return value;
- }
- },
- new PossibleFound.NotFoundAndObtain() {
- @Override public Object doProcess() {
- return DictionaryUtil.nullValue();
- }
- }
- );
- }
- return super.finish(owner);
- } else {
- return false;
- }
- }
-
@Override
public AbstractTracingSpan setOperationName(String operationName) {
if (stackDepth == currentMaxDepth) {
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/ExitSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/ExitSpan.java
index bed47ff12..de9851804 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/ExitSpan.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/ExitSpan.java
@@ -17,32 +17,34 @@ import org.skywalking.apm.network.trace.component.Component;
*
* @author wusheng
*/
-public class ExitSpan extends AbstractTracingSpan {
- private int stackDepth;
+public class ExitSpan extends StackBasedTracingSpan {
private String peer;
private int peerId;
public ExitSpan(int spanId, int parentSpanId, String operationName, String peer) {
super(spanId, parentSpanId, operationName);
- this.stackDepth = 0;
this.peer = peer;
this.peerId = DictionaryUtil.nullValue();
}
public ExitSpan(int spanId, int parentSpanId, int operationId, int peerId) {
super(spanId, parentSpanId, operationId);
- this.stackDepth = 0;
this.peer = null;
this.peerId = peerId;
}
public ExitSpan(int spanId, int parentSpanId, int operationId, String peer) {
super(spanId, parentSpanId, operationId);
- this.stackDepth = 0;
this.peer = peer;
this.peerId = DictionaryUtil.nullValue();
}
+ public ExitSpan(int spanId, int parentSpanId, String operationName, int peerId) {
+ super(spanId, parentSpanId, operationName);
+ this.peer = null;
+ this.peerId = peerId;
+ }
+
/**
* Set the {@link #startTime}, when the first start, which means the first service provided.
*/
@@ -62,15 +64,6 @@ public class ExitSpan extends AbstractTracingSpan {
return this;
}
- @Override
- public boolean finish(TraceSegment owner) {
- if (--stackDepth == 0) {
- return super.finish(owner);
- } else {
- return false;
- }
- }
-
@Override
public AbstractTracingSpan setLayer(SpanLayer layer) {
if (stackDepth == 1) {
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/StackBasedTracingSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/StackBasedTracingSpan.java
new file mode 100644
index 000000000..846e195ed
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/trace/StackBasedTracingSpan.java
@@ -0,0 +1,51 @@
+package org.skywalking.apm.agent.core.context.trace;
+
+import org.skywalking.apm.agent.core.dictionary.DictionaryManager;
+import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
+import org.skywalking.apm.agent.core.dictionary.PossibleFound;
+
+/**
+ * The StackBasedTracingSpan represents a span with an inside stack construction.
+ *
+ * This kind of span can start and finish multi times in a stack-like invoke line.
+ *
+ * @author wusheng
+ */
+public abstract class StackBasedTracingSpan extends AbstractTracingSpan {
+ protected int stackDepth;
+
+ protected StackBasedTracingSpan(int spanId, int parentSpanId, String operationName) {
+ super(spanId, parentSpanId, operationName);
+ this.stackDepth = 0;
+ }
+
+ protected StackBasedTracingSpan(int spanId, int parentSpanId, int operationId) {
+ super(spanId, parentSpanId, operationId);
+ this.stackDepth = 0;
+ }
+
+ @Override
+ public boolean finish(TraceSegment owner) {
+ if (--stackDepth == 0) {
+ if (this.operationId == DictionaryUtil.nullValue()) {
+ this.operationId = (Integer)DictionaryManager.findOperationNameCodeSection()
+ .findOrPrepare4Register(owner.getApplicationId(), operationName)
+ .doInCondition(
+ new PossibleFound.FoundAndObtain() {
+ @Override public Object doProcess(int value) {
+ return value;
+ }
+ },
+ new PossibleFound.NotFoundAndObtain() {
+ @Override public Object doProcess() {
+ return DictionaryUtil.nullValue();
+ }
+ }
+ );
+ }
+ return super.finish(owner);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/match/ClassAnnotationMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/match/ClassAnnotationMatch.java
index 3cc7aabb0..894e37dfb 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/match/ClassAnnotationMatch.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/match/ClassAnnotationMatch.java
@@ -1,5 +1,6 @@
package org.skywalking.apm.agent.core.plugin.match;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.bytebuddy.description.annotation.AnnotationDescription;
@@ -43,7 +44,7 @@ public class ClassAnnotationMatch implements IndirectMatch {
@Override
public boolean isMatch(TypeDescription typeDescription) {
- List annotationList = Arrays.asList(annotations);
+ List annotationList = new ArrayList(Arrays.asList(annotations));
AnnotationList declaredAnnotations = typeDescription.getDeclaredAnnotations();
for (AnnotationDescription annotation : declaredAnnotations) {
annotationList.remove(annotation.getAnnotationType().getActualName());
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/AbstractTracingSpanHelper.java b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/AbstractTracingSpanHelper.java
index c16872e0a..44eaf57a2 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/AbstractTracingSpanHelper.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/AbstractTracingSpanHelper.java
@@ -8,7 +8,7 @@ import org.skywalking.apm.agent.core.context.trace.LogDataEntity;
public class AbstractTracingSpanHelper {
public static int getParentSpanId(AbstractTracingSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "parentSpanId");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "parentSpanId");
} catch (Exception e) {
}
@@ -17,7 +17,7 @@ public class AbstractTracingSpanHelper {
public static List getLogs(AbstractTracingSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "logs");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "logs");
} catch (Exception e) {
}
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/FieldGetter.java b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/FieldGetter.java
index 0aeaad0b9..45c00518f 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/FieldGetter.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/FieldGetter.java
@@ -10,9 +10,10 @@ public class FieldGetter {
return (T)field.get(instance);
}
- public static T getParentFieldValue(Object instance,
+
+ public static T get2LevelParentFieldValue(Object instance,
String fieldName) throws IllegalAccessException, NoSuchFieldException {
- Field field = instance.getClass().getSuperclass().getDeclaredField(fieldName);
+ Field field = instance.getClass().getSuperclass().getSuperclass().getDeclaredField(fieldName);
field.setAccessible(true);
return (T)field.get(instance);
}
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/SpanHelper.java b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/SpanHelper.java
index 1ab112344..802b74215 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/SpanHelper.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/skywalking/apm/agent/core/context/util/SpanHelper.java
@@ -7,7 +7,7 @@ public class SpanHelper {
public static SpanLayer getLayer(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "layer");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "layer");
} catch (Exception e) {
}
@@ -16,7 +16,7 @@ public class SpanHelper {
public static int getComponentId(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "componentId");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "componentId");
} catch (Exception e) {
}
diff --git a/apm-sniffer/apm-agent/pom.xml b/apm-sniffer/apm-agent/pom.xml
index b07bef698..bda4d7137 100644
--- a/apm-sniffer/apm-agent/pom.xml
+++ b/apm-sniffer/apm-agent/pom.xml
@@ -80,6 +80,21 @@
apm-feign-default-http-9.x-plugin
${project.version}
+
+ org.skywalking
+ apm-resttemplate-4.3.x-plugin
+ ${project.version}
+
+
+ org.skywalking
+ apm-spring-concurrent-util-4.x-plugin
+ ${project.version}
+
+
+ org.skywalking
+ apm-springmvc-annotation-4.x-plugin
+ ${project.version}
+
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index 97bf4117a..1b06f19d8 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -22,6 +22,7 @@
okhttp-3.x-plugin
resin-3.x-plugin
resin-4.x-plugin
+ spring-plugins
pom
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/pom.xml
new file mode 100644
index 000000000..d399599fb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/pom.xml
@@ -0,0 +1,24 @@
+
+
+ spring-plugins
+ org.skywalking
+ 3.2-2017
+
+ 4.0.0
+
+ apm-spring-concurrent-util-4.x-plugin
+ jar
+
+ concurrent-util-4.x-plugin
+ http://maven.apache.org
+
+
+
+ org.springframework
+ spring-core
+ 4.3.10.RELEASE
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java
new file mode 100644
index 000000000..6166756be
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java
@@ -0,0 +1,43 @@
+package org.skywalking.apm.plugin.spring.concurrent;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+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 FailureCallbackInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
+ if (cacheValues == null) {
+ return;
+ }
+
+ URI uri = (URI)cacheValues[0];
+ AbstractSpan span = ContextManager.createLocalSpan("future/failureCallback:" + uri.getPath());
+ span.errorOccurred().log((Throwable)allArguments[0]).setComponent(ComponentsDefine.SPRING_REST_TEMPLATE).setLayer(SpanLayer.HTTP);
+ Tags.URL.set(span, uri.getPath());
+ ContextManager.continued((ContextSnapshot)cacheValues[2]);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ 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/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java
new file mode 100644
index 000000000..a2cdb5a11
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java
@@ -0,0 +1,43 @@
+package org.skywalking.apm.plugin.spring.concurrent;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+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 SuccessCallbackInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
+ if (cacheValues == null) {
+ return;
+ }
+
+ URI uri = (URI)cacheValues[0];
+ AbstractSpan span = ContextManager.createLocalSpan("future/successCallback:" + uri.getPath());
+ span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE).setLayer(SpanLayer.HTTP);
+ Tags.URL.set(span, uri.getPath());
+ ContextManager.continued((ContextSnapshot)cacheValues[2]);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ 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/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/FailureCallbackInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/FailureCallbackInstrumentation.java
new file mode 100644
index 000000000..27d79b566
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/FailureCallbackInstrumentation.java
@@ -0,0 +1,56 @@
+package org.skywalking.apm.plugin.spring.concurrent.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+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 org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.plugin.spring.concurrent.match.FailedCallbackMatch.failedCallbackMatch;
+
+/**
+ * {@link FailureCallbackInstrumentation} enhance the onFailure method that class inherited
+ * org.springframework.util.concurrent.FailureCallback by {@link FailureCallbackInterceptor}.
+ *
+ * @author zhangxin
+ */
+public class FailureCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ public static final String FAILURE_CALLBACK_INTERCEPTOR = "org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor";
+ public static final String FAILURE_METHOD_NAME = "onFailure";
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(FAILURE_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return FAILURE_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return failedCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java
new file mode 100644
index 000000000..fc1b27111
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java
@@ -0,0 +1,69 @@
+package org.skywalking.apm.plugin.spring.concurrent.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+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 static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.plugin.spring.concurrent.match.ListenableFutureCallbackMatch.listenableFutureCallbackMatch;
+
+/**
+ * {@link ListenableFutureCallbackInstrumentation} enhance onSuccess method and oonFailure
+ * that class inherited org.springframework.util.concurrent.ListenableFutureCallback by
+ * org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor and
+ * org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor.
+ *
+ * @author zhangxin
+ */
+public class ListenableFutureCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(SuccessCallbackInstrumentation.SUCCESS_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return SuccessCallbackInstrumentation.SUCCESS_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(FailureCallbackInstrumentation.FAILURE_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return FailureCallbackInstrumentation.FAILURE_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return listenableFutureCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java
new file mode 100644
index 000000000..51c7db24d
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java
@@ -0,0 +1,50 @@
+package org.skywalking.apm.plugin.spring.concurrent.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+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 static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.plugin.spring.concurrent.match.SuccessCallbackMatch.successCallbackMatch;
+
+/**
+ * {@link SuccessCallbackInstrumentation} enhance the onSuccess method that class inherited
+ * org.springframework.util.concurrent.SuccessCallback by org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor.
+ *
+ * @author zhangxin
+ */
+public class SuccessCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ public static final String SUCCESS_CALLBACK_INTERCEPTOR =
+ "org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor";
+ public static final String SUCCESS_METHOD_NAME = "onSuccess";
+
+ @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(SUCCESS_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return SUCCESS_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override protected ClassMatch enhanceClass() {
+ return successCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/EitherInterfaceMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/EitherInterfaceMatch.java
new file mode 100644
index 000000000..1396c6d20
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/EitherInterfaceMatch.java
@@ -0,0 +1,77 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
+import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+
+/**
+ * {@link EitherInterfaceMatch} match the class inherited {@link #getMatchInterface() } and not inherited {@link
+ * #getMutexInterface()}
+ *
+ * @author zhangxin
+ */
+public abstract class EitherInterfaceMatch implements IndirectMatch {
+
+ private static final String SPRING_PACKAGE_PREFIX = "org.springframework";
+ private static final String OBJECT_CLASS_NAME = "java.lang.Object";
+
+ protected EitherInterfaceMatch() {
+
+ }
+
+ @Override
+ public ElementMatcher.Junction buildJunction() {
+ return not(nameStartsWith(SPRING_PACKAGE_PREFIX)).
+ and(hasSuperType(named(getMatchInterface())))
+ .and(not(hasSuperType(named(getMutexInterface()))));
+ }
+
+ @Override
+ public boolean isMatch(TypeDescription typeDescription) {
+ MatchResult matchResult = new MatchResult();
+ for (TypeDescription.Generic generic : typeDescription.getInterfaces()) {
+ matchHierarchyClazz(generic, matchResult);
+ }
+
+ matchHierarchyClazz(typeDescription.getSuperClass(), matchResult);
+ return matchResult.result();
+ }
+
+ public abstract String getMatchInterface();
+
+ public abstract String getMutexInterface();
+
+ private void matchHierarchyClazz(TypeDescription.Generic clazz, MatchResult matchResult) {
+ if (clazz.asRawType().getTypeName().equals(getMutexInterface())) {
+ matchResult.findMutexInterface = true;
+ return;
+ }
+
+ if (clazz.asRawType().getTypeName().equals(getMatchInterface())) {
+ matchResult.findMatchInterface = true;
+ }
+
+ for (TypeDescription.Generic generic : clazz.getInterfaces()) {
+ matchHierarchyClazz(generic, matchResult);
+ }
+
+ TypeDescription.Generic superClazz = clazz.getSuperClass();
+ if (superClazz != null && !clazz.getTypeName().equals(OBJECT_CLASS_NAME)) {
+ matchHierarchyClazz(superClazz, matchResult);
+ }
+ }
+
+ private static class MatchResult {
+ private boolean findMatchInterface = false;
+ private boolean findMutexInterface = false;
+
+ public boolean result() {
+ return findMatchInterface && !findMutexInterface;
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/FailedCallbackMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/FailedCallbackMatch.java
new file mode 100644
index 000000000..abcfde249
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/FailedCallbackMatch.java
@@ -0,0 +1,31 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+/**
+ * {@link FailedCallbackMatch} match the class that inherited org.springframework.util.concurrent.FailureCallback
+ * and not inherited org.springframework.util.concurrent.SuccessCallback
+ *
+ * @author zhangxin
+ */
+public class FailedCallbackMatch extends EitherInterfaceMatch {
+
+ private static final String MATCH_INTERFACE = "org.springframework.util.concurrent.FailureCallback";
+ private static final String MUTEX_INTERFACE = "org.springframework.util.concurrent.SuccessCallback";
+
+ private FailedCallbackMatch() {
+
+ }
+
+ @Override public String getMatchInterface() {
+ return MATCH_INTERFACE;
+ }
+
+ @Override public String getMutexInterface() {
+ return MUTEX_INTERFACE;
+ }
+
+ public static ClassMatch failedCallbackMatch() {
+ return new FailedCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/ListenableFutureCallbackMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/ListenableFutureCallbackMatch.java
new file mode 100644
index 000000000..a18cf6f01
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/ListenableFutureCallbackMatch.java
@@ -0,0 +1,65 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
+import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+
+/**
+ * {@link ListenableFutureCallbackMatch} match the class that inherited org.springframework.util.concurrent.ListenableFutureCallback.
+ *
+ * @author zhangxin
+ */
+public class ListenableFutureCallbackMatch implements IndirectMatch {
+
+ private static final String LISTENABLE_FUTURE_CALLBACK_CLASS_NAME = "org.springframework.util.concurrent.ListenableFutureCallback";
+
+ private ListenableFutureCallbackMatch() {
+
+ }
+
+ @Override
+ public ElementMatcher.Junction buildJunction() {
+ return not(nameStartsWith("org.springframework")).
+ and(hasSuperType(named(LISTENABLE_FUTURE_CALLBACK_CLASS_NAME)));
+ }
+
+ @Override
+ public boolean isMatch(TypeDescription typeDescription) {
+ boolean isMatch = false;
+ for (TypeDescription.Generic generic : typeDescription.getInterfaces()) {
+ isMatch = isMatch || matchExactClass(generic);
+ }
+
+ return isMatch || matchExactClass(typeDescription.getSuperClass());
+ }
+
+ private boolean matchExactClass(TypeDescription.Generic clazz) {
+ if (clazz.asRawType().getTypeName().equals(LISTENABLE_FUTURE_CALLBACK_CLASS_NAME)) {
+ return true;
+ }
+
+ boolean isMatch = false;
+ for (TypeDescription.Generic generic : clazz.getInterfaces()) {
+ isMatch = isMatch || matchExactClass(generic);
+ }
+
+ if (!isMatch) {
+ TypeDescription.Generic superClazz = clazz.getSuperClass();
+ if (superClazz != null && !clazz.getTypeName().equals("java.lang.Object")) {
+ isMatch = isMatch || matchExactClass(superClazz);
+ }
+ }
+
+ return isMatch;
+ }
+
+ public static ClassMatch listenableFutureCallbackMatch() {
+ return new ListenableFutureCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/SuccessCallbackMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/SuccessCallbackMatch.java
new file mode 100644
index 000000000..309767198
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/SuccessCallbackMatch.java
@@ -0,0 +1,32 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+/**
+ * {@link SuccessCallbackMatch} match the class that inherited org.springframework.util.concurrent.SuccessCallback
+ * and not inherited org.springframework.util.concurrent.FailureCallback
+ *
+ * @author zhangxin
+ */
+public class SuccessCallbackMatch extends EitherInterfaceMatch {
+
+ private static final String MATCH_INTERFACE = "org.springframework.util.concurrent.SuccessCallback";
+ private static final String MUTEX_INTERFACE = "org.springframework.util.concurrent.FailureCallback";
+
+ private SuccessCallbackMatch() {
+ }
+
+ @Override
+ public String getMatchInterface() {
+ return MATCH_INTERFACE;
+ }
+
+ @Override
+ public String getMutexInterface() {
+ return MUTEX_INTERFACE;
+ }
+
+ public static ClassMatch successCallbackMatch() {
+ return new SuccessCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..795a7685c
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,3 @@
+spring-concurrent-util-4.x=org.skywalking.apm.plugin.spring.concurrent.define.FailureCallbackInstrumentation
+spring-concurrent-util-4.x=org.skywalking.apm.plugin.spring.concurrent.define.SuccessCallbackInstrumentation
+spring-concurrent-util-4.x=org.skywalking.apm.plugin.spring.concurrent.define.ListenableFutureCallbackInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/pom.xml
new file mode 100644
index 000000000..bb88c3441
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/pom.xml
@@ -0,0 +1,36 @@
+
+
+ spring-plugins
+ org.skywalking
+ 3.2-2017
+
+ 4.0.0
+
+ apm-springmvc-annotation-4.x-plugin
+ jar
+
+ mvc-annotation-4.x-plugin
+ http://maven.apache.org
+
+
+
+ org.springframework
+ spring-core
+ 4.3.10.RELEASE
+ provided
+
+
+ org.springframework
+ spring-webmvc
+ 4.3.8.RELEASE
+ provided
+
+
+ javax.servlet
+ javax.servlet-api
+ 4.0.0-b01
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/ControllerConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/ControllerConstructorInterceptor.java
new file mode 100644
index 000000000..5f3d39ed0
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/ControllerConstructorInterceptor.java
@@ -0,0 +1,32 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * The ControllerConstructorInterceptor intercepts the Controller's constructor, in order to acquire the
+ * mapping annotation, if exist.
+ *
+ * But, you can see we only use the first mapping value, Why?
+ *
+ * Right now, we intercept the controller by annotation as you known, so we CAN'T know which uri patten is actually
+ * matched. Even we know, that costs a lot.
+ *
+ * If we want to resolve that, we must intercept the Spring MVC core codes, that is not a good choice for now.
+ *
+ * Comment by @wu-sheng
+ */
+public class ControllerConstructorInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ String basePath = "";
+ RequestMapping basePathRequestMapping = objInst.getClass().getAnnotation(RequestMapping.class);
+ if (basePathRequestMapping != null) {
+ basePath = basePathRequestMapping.value()[0];
+ }
+ PathMappingCache pathMappingCache = new PathMappingCache(basePath);
+ objInst.setSkyWalkingDynamicField(pathMappingCache);
+ }
+}
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/ControllerServiceMethodInterceptor.java
new file mode 100644
index 000000000..32b4cb42d
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/ControllerServiceMethodInterceptor.java
@@ -0,0 +1,64 @@
+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.conf.Config;
+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;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+/**
+ * The ControllerServiceMethodInterceptor only use the first mapping value.
+ *
+ * @See {@link ControllerConstructorInterceptor} to explain why we are doing this.
+ */
+public class ControllerServiceMethodInterceptor 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) {
+ requestURL = method.getAnnotation(RequestMapping.class).value()[0];
+ pathMappingCache.addPathMapping(method, requestURL.toString());
+ }
+
+ HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
+ String tracingHeaderValue = request.getHeader(Config.Plugin.Propagation.HEADER_NAME);
+ ContextCarrier contextCarrier = new ContextCarrier().deserialize(tracingHeaderValue);
+ AbstractSpan span = ContextManager.createEntrySpan(requestURL, contextCarrier);
+ Tags.URL.set(span, request.getRequestURL().toString());
+ Tags.HTTP.METHOD.set(span, request.getMethod());
+ span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
+ SpanLayer.asHttp(span);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
+
+ 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/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/PathMappingCache.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/PathMappingCache.java
new file mode 100644
index 000000000..591891433
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/PathMappingCache.java
@@ -0,0 +1,28 @@
+package org.skywalking.apm.plugin.spring.mvc;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The PathMappingCache represents a field
+ *
+ *
+ * @author wusheng
+ */
+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/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
new file mode 100644
index 000000000..96f7715d7
--- /dev/null
+++ 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
@@ -0,0 +1,76 @@
+package org.skywalking.apm.plugin.spring.mvc.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+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 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;
+
+/**
+ * {@link ControllerInstrumentation} enhance all constructor and method annotated with
+ * org.springframework.web.bind.annotation.RequestMapping that class has
+ * org.springframework.stereotype.Controller annotation.
+ *
+ * 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
+ * combine the path value of current annotation on current method and the base path and set the new path to the dynamic
+ * filed
+ *
+ * @author zhangxin
+ */
+public abstract class AbstractControllerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return "org.skywalking.apm.plugin.spring.mvc.ControllerConstructorInterceptor";
+ }
+ }
+ };
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return isAnnotatedWith(named("org.springframework.web.bind.annotation.RequestMapping"));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return "org.skywalking.apm.plugin.spring.mvc.ControllerServiceMethodInterceptor";
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byClassAnnotationMatch(getEnhanceAnnotations());
+ }
+
+ protected abstract String[] getEnhanceAnnotations();
+}
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/ControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/ControllerInstrumentation.java
new file mode 100644
index 000000000..abfdf8e29
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/ControllerInstrumentation.java
@@ -0,0 +1,10 @@
+package org.skywalking.apm.plugin.spring.mvc.define;
+
+public class ControllerInstrumentation extends AbstractControllerInstrumentation {
+
+ public static final String ENHANCE_ANNOTATION = "org.springframework.stereotype.Controller";
+
+ @Override protected String[] getEnhanceAnnotations() {
+ return new String[] {ENHANCE_ANNOTATION};
+ }
+}
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/RestControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/RestControllerInstrumentation.java
new file mode 100644
index 000000000..8ce6e59e6
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/mvc/define/RestControllerInstrumentation.java
@@ -0,0 +1,10 @@
+package org.skywalking.apm.plugin.spring.mvc.define;
+
+public class RestControllerInstrumentation extends AbstractControllerInstrumentation {
+
+ public static final String ENHANCE_ANNOTATION = "org.springframework.web.bind.annotation.RestController";
+
+ @Override protected String[] getEnhanceAnnotations() {
+ return new String[] {ENHANCE_ANNOTATION};
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..92d3695ba
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,2 @@
+spring-mvc-annotation-4.x=org.skywalking.apm.plugin.spring.mvc.define.ControllerInstrumentation
+spring-mvc-annotation-4.x=org.skywalking.apm.plugin.spring.mvc.define.RestControllerInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
new file mode 100644
index 000000000..0a91d8890
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
@@ -0,0 +1,27 @@
+
+
+ 4.0.0
+
+
+ org.skywalking
+ apm-sdk-plugin
+ 3.2-2017
+
+
+ spring-plugins
+
+ concurrent-util-4.x-plugin
+ resttemplate-4.x-plugin
+ mvc-annotation-4.x-plugin
+
+ pom
+
+ apm-sdk-plugin
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/pom.xml
new file mode 100644
index 000000000..874a25df4
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/pom.xml
@@ -0,0 +1,24 @@
+
+
+ spring-plugins
+ org.skywalking
+ 3.2-2017
+
+ 4.0.0
+
+ apm-resttemplate-4.3.x-plugin
+ jar
+
+ resttemplate-4.3.x-plugin
+ http://maven.apache.org
+
+
+
+ org.springframework
+ spring-web
+ 4.3.10.RELEASE
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java
new file mode 100644
index 000000000..218113022
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java
@@ -0,0 +1,32 @@
+package org.skywalking.apm.plugin.spring.resttemplate.async;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
+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;
+
+public class FutureGetInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
+ ContextManager.createLocalSpan("future/get:" + ((URI)cacheValues[0]).getPath());
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ AbstractSpan activeSpan = ContextManager.activeSpan();
+ activeSpan.errorOccurred().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/ResponseCallBackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/ResponseCallBackInterceptor.java
new file mode 100644
index 000000000..421312ebe
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/ResponseCallBackInterceptor.java
@@ -0,0 +1,32 @@
+package org.skywalking.apm.plugin.spring.resttemplate.async;
+
+import java.lang.reflect.Method;
+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;
+
+public class ResponseCallBackInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ EnhancedInstance successCallBak = (EnhancedInstance)allArguments[0];
+ successCallBak.setSkyWalkingDynamicField(objInst.getSkyWalkingDynamicField());
+
+ if (allArguments.length == 2) {
+ EnhancedInstance failedCallBack = (EnhancedInstance)allArguments[1];
+ failedCallBack.setSkyWalkingDynamicField(objInst.getSkyWalkingDynamicField());
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ return ret;
+ }
+
+ @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/RestExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/RestExecuteInterceptor.java
new file mode 100644
index 000000000..4ee3e2581
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/RestExecuteInterceptor.java
@@ -0,0 +1,53 @@
+package org.skywalking.apm.plugin.spring.resttemplate.async;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+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;
+import org.springframework.http.HttpMethod;
+
+public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ final URI requestURL = (URI)allArguments[0];
+ final HttpMethod httpMethod = (HttpMethod)allArguments[1];
+ final ContextCarrier contextCarrier = new ContextCarrier();
+ String remotePeer = requestURL.getHost() + ":" + requestURL.getPort();
+ AbstractSpan span = ContextManager.createExitSpan(requestURL.getPath(), contextCarrier, remotePeer);
+
+ span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE);
+ Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath());
+ Tags.HTTP.METHOD.set(span, httpMethod.toString());
+ SpanLayer.asHttp(span);
+ Object[] cacheValues = new Object[3];
+ cacheValues[0] = requestURL;
+ cacheValues[1] = contextCarrier.serialize();
+ objInst.setSkyWalkingDynamicField(cacheValues);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
+ cacheValues[2] = ContextManager.capture();
+ if (ret != null) {
+ ((EnhancedInstance)ret).setSkyWalkingDynamicField(cacheValues);
+ }
+ 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/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/ResponseExtractorFutureInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/ResponseExtractorFutureInstrumentation.java
new file mode 100644
index 000000000..858fe5a7f
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/ResponseExtractorFutureInstrumentation.java
@@ -0,0 +1,77 @@
+package org.skywalking.apm.plugin.spring.resttemplate.async.define;
+
+import java.net.URI;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+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 org.skywalking.apm.plugin.spring.resttemplate.async.ResponseCallBackInterceptor;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * {@link ResponseExtractorFutureInstrumentation} enhance the addCallback method and get method of
+ * org.springframework.web.client.AsyncRestTemplate$ResponseExtractorFuture by
+ * org.skywalking.apm.plugin.spring.resttemplate.async.ResponseCallBackInterceptor and
+ * org.skywalking.apm.plugin.spring.resttemplate.async.FutureGetInterceptor.
+ *
+ * {@link ResponseCallBackInterceptor} set the {@link URI} and {@link ContextSnapshot} to inherited
+ * org.springframework.util.concurrent.SuccessCallback and org.springframework.util.concurrent.FailureCallback
+ *
+ * @author zhangxin
+ */
+public class ResponseExtractorFutureInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ADD_CALLBACK_METHOD_NAME = "addCallback";
+ private static final String ADD_CALLBACK_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.async.ResponseCallBackInterceptor";
+ private static final String ENHANCE_CLASS = "org.springframework.web.client.AsyncRestTemplate$ResponseExtractorFuture";
+ private static final String GET_METHOD_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.async.FutureGetInterceptor";
+ private static final String GET_METHOD_NAME = "get";
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(ADD_CALLBACK_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return ADD_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(GET_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return GET_METHOD_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/RestTemplateInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/RestTemplateInstrumentation.java
new file mode 100644
index 000000000..1cb6a20b0
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/RestTemplateInstrumentation.java
@@ -0,0 +1,75 @@
+package org.skywalking.apm.plugin.spring.resttemplate.async.define;
+
+import java.net.URI;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+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 static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * {@link RestTemplateInstrumentation} enhance the doExecute method and createAsyncRequest
+ * method of org.springframework.web.client.AsyncRestTemplate by org.skywalking.apm.plugin.spring.resttemplate.async.RestExecuteInterceptor
+ * and org.springframework.http.client.RestRequestInterceptor.
+ *
+ * org.springframework.http.client.RestRequestInterceptor set {@link URI} and {@link ContextSnapshot} to
+ * org.springframework.web.client.AsyncRestTemplate$ResponseExtractorFuture for propagate trace context
+ * after execute doExecute .
+ *
+ * @author zhangxin
+ */
+public class RestTemplateInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "org.springframework.web.client.AsyncRestTemplate";
+ private static final String DO_EXECUTE_METHOD_NAME = "doExecute";
+ private static final String DO_EXECUTE_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.async.RestExecuteInterceptor";
+ private static final String CREATE_REQUEST_METHOD_NAME = "createAsyncRequest";
+ private static final String CREATE_REQUEST_INTERCEPTOR = "org.springframework.http.client.RestRequestInterceptor";
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(DO_EXECUTE_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return DO_EXECUTE_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(CREATE_REQUEST_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return CREATE_REQUEST_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestExecuteInterceptor.java
new file mode 100644
index 000000000..a0764191b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestExecuteInterceptor.java
@@ -0,0 +1,46 @@
+package org.skywalking.apm.plugin.spring.resttemplate.sync;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+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;
+import org.springframework.http.HttpMethod;
+
+public class RestExecuteInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ final URI requestURL = (URI)allArguments[0];
+ final HttpMethod httpMethod = (HttpMethod)allArguments[1];
+ final ContextCarrier contextCarrier = new ContextCarrier();
+ String remotePeer = requestURL.getHost() + ":" + requestURL.getPort();
+ AbstractSpan span = ContextManager.createExitSpan(requestURL.getPath(), contextCarrier, remotePeer);
+
+ span.setComponent(ComponentsDefine.SPRING_REST_TEMPLATE);
+ Tags.URL.set(span, requestURL.getScheme() + "://" + requestURL.getHost() + ":" + requestURL.getPort() + requestURL.getPath());
+ Tags.HTTP.METHOD.set(span, httpMethod.toString());
+ SpanLayer.asHttp(span);
+
+ objInst.setSkyWalkingDynamicField(contextCarrier.serialize());
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ 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/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestRequestInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestRequestInterceptor.java
new file mode 100644
index 000000000..23e062c5b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestRequestInterceptor.java
@@ -0,0 +1,34 @@
+package org.skywalking.apm.plugin.spring.resttemplate.sync;
+
+import java.lang.reflect.Method;
+import org.skywalking.apm.agent.core.conf.Config;
+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.springframework.http.client.AbstractClientHttpRequest;
+import org.springframework.http.client.ClientHttpRequest;
+
+public class RestRequestInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ClientHttpRequest clientHttpRequest = (ClientHttpRequest)ret;
+ if (clientHttpRequest instanceof AbstractClientHttpRequest) {
+ AbstractClientHttpRequest httpRequest = (AbstractClientHttpRequest)clientHttpRequest;
+ httpRequest.getHeaders().set(Config.Plugin.Propagation.HEADER_NAME, String.valueOf(objInst.getSkyWalkingDynamicField()));
+ }
+ return ret;
+ }
+
+ @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestResponseInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestResponseInterceptor.java
new file mode 100644
index 000000000..80e554f52
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestResponseInterceptor.java
@@ -0,0 +1,38 @@
+package org.skywalking.apm.plugin.spring.resttemplate.sync;
+
+import java.lang.reflect.Method;
+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.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.springframework.http.client.ClientHttpResponse;
+
+public class RestResponseInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+
+ ClientHttpResponse response = (ClientHttpResponse)allArguments[2];
+ int statusCode = response.getStatusCode().value();
+ AbstractSpan span = ContextManager.activeSpan();
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ Tags.STATUS_CODE.set(span, Integer.toString(statusCode));
+ }
+ 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/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/define/RestTemplateInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/define/RestTemplateInstrumentation.java
new file mode 100644
index 000000000..9fb529bf1
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/define/RestTemplateInstrumentation.java
@@ -0,0 +1,89 @@
+package org.skywalking.apm.plugin.spring.resttemplate.sync.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+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 static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * {@link RestTemplateInstrumentation} enhance the doExecute method,handleResponse method and
+ * handleResponse method of org.springframework.web.client.RestTemplate by
+ * org.skywalking.apm.plugin.spring.resttemplate.sync.RestExecuteInterceptor,
+ * org.skywalking.apm.plugin.spring.resttemplate.sync.RestResponseInterceptor and
+ * org.skywalking.apm.plugin.spring.resttemplate.sync.RestRequestInterceptor.
+ *
+ * org.skywalking.apm.plugin.spring.resttemplate.sync.RestResponseInterceptor set context to header for
+ * propagate trace context after execute createRequest.
+ *
+ * @author zhangxin
+ */
+public class RestTemplateInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "org.springframework.web.client.RestTemplate";
+ private static final String DO_EXECUTE_METHOD_NAME = "doExecute";
+ private static final String DO_EXECUTE_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.sync.RestExecuteInterceptor";
+ private static final String HANDLE_REQUEST_METHOD_NAME = "handleResponse";
+ private static final String HAND_REQUEST_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.sync.RestResponseInterceptor";
+ private static final String CREATE_REQUEST_METHOD_NAME = "createRequest";
+ private static final String CREATE_REQUEST_INTERCEPTOR = "org.skywalking.apm.plugin.spring.resttemplate.sync.RestRequestInterceptor";
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(DO_EXECUTE_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return DO_EXECUTE_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(HANDLE_REQUEST_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return HAND_REQUEST_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(CREATE_REQUEST_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return CREATE_REQUEST_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/springframework/http/client/RestRequestInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/springframework/http/client/RestRequestInterceptor.java
new file mode 100644
index 000000000..f8bde0b91
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/java/org/springframework/http/client/RestRequestInterceptor.java
@@ -0,0 +1,31 @@
+package org.springframework.http.client;
+
+import java.lang.reflect.Method;
+import org.skywalking.apm.agent.core.conf.Config;
+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;
+
+public class RestRequestInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ AbstractAsyncClientHttpRequest clientHttpRequest = (AbstractAsyncClientHttpRequest)ret;
+ if (ret != null) {
+ clientHttpRequest.getHeaders().set(Config.Plugin.Propagation.HEADER_NAME, String.valueOf(((Object[])objInst.getSkyWalkingDynamicField())[1]));
+ }
+ return ret;
+ }
+
+ @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..aa695c514
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,3 @@
+spring-resttemplate-4.x=org.skywalking.apm.plugin.spring.resttemplate.async.define.RestTemplateInstrumentation
+spring-resttemplate-4.x=org.skywalking.apm.plugin.spring.resttemplate.async.define.ResponseExtractorFutureInstrumentation
+spring-resttemplate-4.x=org.skywalking.apm.plugin.spring.resttemplate.sync.define.RestTemplateInstrumentation
diff --git a/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/FieldGetter.java b/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/FieldGetter.java
index 1710b93ca..b2bb6f464 100644
--- a/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/FieldGetter.java
+++ b/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/FieldGetter.java
@@ -16,4 +16,12 @@ public class FieldGetter {
field.setAccessible(true);
return (T)field.get(instance);
}
+
+
+ public static T get2LevelParentFieldValue(Object instance,
+ String fieldName) throws IllegalAccessException, NoSuchFieldException {
+ Field field = instance.getClass().getSuperclass().getSuperclass().getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return (T)field.get(instance);
+ }
}
diff --git a/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/SpanHelper.java b/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/SpanHelper.java
index 3620fa741..0b752e947 100644
--- a/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/SpanHelper.java
+++ b/apm-sniffer/apm-test-tools/src/main/java/org/skywalking/apm/agent/test/helper/SpanHelper.java
@@ -10,8 +10,13 @@ import org.skywalking.apm.agent.core.context.util.KeyValuePair;
public class SpanHelper {
public static int getParentSpanId(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "parentSpanId");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "parentSpanId");
} catch (Exception e) {
+ try {
+ return FieldGetter.getParentFieldValue(tracingSpan, "parentSpanId");
+ } catch (Exception e1) {
+
+ }
}
return -9999;
@@ -19,8 +24,13 @@ public class SpanHelper {
public static List getLogs(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "logs");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "logs");
} catch (Exception e) {
+ try {
+ return FieldGetter.getParentFieldValue(tracingSpan, "logs");
+ } catch (Exception e1) {
+
+ }
}
return Collections.emptyList();
@@ -28,8 +38,13 @@ public class SpanHelper {
public static List getTags(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "tags");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "tags");
} catch (Exception e) {
+ try {
+ return FieldGetter.getParentFieldValue(tracingSpan, "tags");
+ } catch (Exception e1) {
+
+ }
}
return Collections.emptyList();
@@ -37,8 +52,13 @@ public class SpanHelper {
public static SpanLayer getLayer(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "layer");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "layer");
} catch (Exception e) {
+ try {
+ return FieldGetter.getParentFieldValue(tracingSpan, "layer");
+ } catch (Exception e1) {
+
+ }
}
return null;
@@ -46,8 +66,13 @@ public class SpanHelper {
public static String getComponentName(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "componentName");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "componentName");
} catch (Exception e) {
+ try {
+ return FieldGetter.getParentFieldValue(tracingSpan, "componentName");
+ } catch (Exception e1) {
+
+ }
}
return null;
@@ -55,8 +80,13 @@ public class SpanHelper {
public static int getComponentId(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "componentId");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "componentId");
} catch (Exception e) {
+ try {
+ return FieldGetter.getParentFieldValue(tracingSpan, "componentId");
+ } catch (Exception e1) {
+
+ }
}
return -1;
@@ -64,8 +94,13 @@ public class SpanHelper {
public static boolean getErrorOccurred(AbstractSpan tracingSpan) {
try {
- return FieldGetter.getParentFieldValue(tracingSpan, "errorOccurred");
+ return FieldGetter.get2LevelParentFieldValue(tracingSpan, "errorOccurred");
} catch (Exception e) {
+ try {
+ return FieldGetter.getParentFieldValue(tracingSpan, "errorOccurred");
+ } catch (Exception e1) {
+
+ }
}
return false;