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 912efa40c4439ebd2d7e3b739432c8ed4c1dd109..d70e567877a066bbde8171f7e3422d573aa2fce4 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,8 @@ public class ComponentsDefine { public static final OfficialComponent OKHTTP = new OfficialComponent(12, "OKHttp"); + public static final OfficialComponent REST_TEMPLATE = new OfficialComponent(13, "RestTemplate"); + private static ComponentsDefine instance = new ComponentsDefine(); private String[] components; @@ -40,7 +42,7 @@ public class ComponentsDefine { } public ComponentsDefine() { - components = new String[13]; + components = new String[14]; addComponent(TOMCAT); addComponent(HTTPCLIENT); addComponent(DUBBO); @@ -53,6 +55,7 @@ public class ComponentsDefine { addComponent(RESIN); addComponent(FEIGN); addComponent(OKHTTP); + addComponent(REST_TEMPLATE); } private void addComponent(OfficialComponent component) { diff --git a/apm-sniffer/apm-agent/pom.xml b/apm-sniffer/apm-agent/pom.xml index b07bef698acdf520f7322bc90fc9427eb7430531..11c5388f879afc3a3446f2c93ac45634d50304e2 100644 --- a/apm-sniffer/apm-agent/pom.xml +++ b/apm-sniffer/apm-agent/pom.xml @@ -80,6 +80,16 @@ apm-feign-default-http-9.x-plugin ${project.version} + + org.skywalking + apm-resttemplate-plugin + ${project.version} + + + org.skywalking + apm-spring-concurrent-util-plugin + ${project.version} + diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index 97bf4117a2a89a19539ad96f296f5f38dd2e5ac7..1b06f19d82cd2400a9d13cf33b4f2c5243a5eda7 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.3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..2e3fd3b4f1463fabb0305b785c97cae41c274702 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/pom.xml @@ -0,0 +1,24 @@ + + + spring-plugins + org.skywalking + 3.2-2017 + + 4.0.0 + + apm-spring-concurrent-util-plugin + jar + + concurrent-util-4.3.x-plugin + http://maven.apache.org + + + + org.springframework + spring-core + 4.3.8.RELEASE + provided + + + diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..56ae40584e817f4358c16bbdcfb471f2147783f7 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java @@ -0,0 +1,44 @@ +package org.skywalking.apm.plugin.spring.concurrent; + +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, String methodName, 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.REST_TEMPLATE).setLayer(SpanLayer.HTTP); + Tags.URL.set(span, uri.getPath()); + ContextManager.continued((ContextSnapshot)cacheValues[2]); + } + + @Override + public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..482a88638416b01c56fa97d9d399a0eeba24628b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java @@ -0,0 +1,41 @@ +package org.skywalking.apm.plugin.spring.concurrent; + +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, String methodName, 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.REST_TEMPLATE).setLayer(SpanLayer.HTTP); + Tags.URL.set(span, uri.getPath()); + ContextManager.continued((ContextSnapshot)cacheValues[2]); + } + + @Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/FailureCallbackInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..27d79b56639fbcdf54ce3eaec6e1d1dec0f17729 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.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.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..74ebbcad7c7e204f576855f0c08c931222389892 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java @@ -0,0 +1,65 @@ +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 org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor; + +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 {@link + * SuccessCallbackInterceptor} and {@link 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.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..4be5c33811e8a9c0c4d444b187dae420020cee52 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java @@ -0,0 +1,51 @@ +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 org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor; + +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 {@link 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.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/EitherInterfaceMatch.java new file mode 100644 index 0000000000000000000000000000000000000000..1396c6d2097b75608f8b0fdc17c33d49a9ba27cc --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.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.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/FailedCallbackMatch.java new file mode 100644 index 0000000000000000000000000000000000000000..abcfde2497ade293dd4970d16c4dca09893a4007 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.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.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/ListenableFutureCallbackMatch.java new file mode 100644 index 0000000000000000000000000000000000000000..a18cf6f019cb08be42107c6546292bc151fa9e50 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.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.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/SuccessCallbackMatch.java new file mode 100644 index 0000000000000000000000000000000000000000..309767198e639b59df25b2a04477adb02292566b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.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.3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 0000000000000000000000000000000000000000..8c9426546886aa15c0ed91ccabf66147becd952b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,3 @@ +spring-concurrent-util-4.3.8=org.skywalking.apm.plugin.spring.concurrent.define.FailureCallbackInstrumentation +spring-concurrent-util-4.3.8=org.skywalking.apm.plugin.spring.concurrent.define.SuccessCallbackInstrumentation +spring-concurrent-util-4.3.8=org.skywalking.apm.plugin.spring.concurrent.define.ListenableFutureCallbackInstrumentation 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 0000000000000000000000000000000000000000..a7558877d00abddaba55b1fcbd9596d2e4c9c6cf --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + + org.skywalking + apm-sdk-plugin + 3.2-2017 + + + spring-plugins + + concurrent-util-4.3.x-plugin + resttemplate-4.3.x-plugin + + pom + + apm-sdk-plugin + http://maven.apache.org + + + UTF-8 + + + diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..3dde8eb50b6d09362f9b369ebc2db3315198d474 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/pom.xml @@ -0,0 +1,24 @@ + + + spring-plugins + org.skywalking + 3.2-2017 + + 4.0.0 + + apm-resttemplate-plugin + jar + + resttemplate-4.3.x-plugin + http://maven.apache.org + + + + org.springframework + spring-web + 4.3.8.RELEASE + provided + + + diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..102ba4e3bac38db54d3cf90df6ff150bbb2631a5 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java @@ -0,0 +1,33 @@ +package org.skywalking.apm.plugin.spring.resttemplate.async; + +import com.google.instrumentation.trace.Span; +import java.net.URI; +import java.util.List; +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, String methodName, Object[] allArguments, + Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + List cacheValues = (List)objInst.getSkyWalkingDynamicField(); + ContextManager.createLocalSpan("future/get:" + ((URI)cacheValues.get(0)).getPath()); + } + + @Override + public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, String methodName, 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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/ResponseCallBackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/ResponseCallBackInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..ab4cc2dd8e584aed9a7b6ab4a6dfc08e19b73eac --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/ResponseCallBackInterceptor.java @@ -0,0 +1,29 @@ +package org.skywalking.apm.plugin.spring.resttemplate.async; + +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, String methodName, 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, String methodName, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/RestExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/RestExecuteInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..378ad6da6da3d67630be1e782af75556775bfda2 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/RestExecuteInterceptor.java @@ -0,0 +1,51 @@ +package org.skywalking.apm.plugin.spring.resttemplate.async; + +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, String methodName, 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.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, String methodName, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField(); + cacheValues[3] = ContextManager.capture(); + ((EnhancedInstance)ret).setSkyWalkingDynamicField(cacheValues); + ContextManager.stopSpan(); + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/ResponseExtractorFutureInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..858fe5a7feb365051c292e892abed7d76ba4760a --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.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.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/RestTemplateInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..622ee4fe8587f139d10efe510c5db5829c2ab058 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/define/RestTemplateInstrumentation.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.FutureGetInterceptor; +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 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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestExecuteInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..0fb1bec8f229e4fee6f4fc4eb7a1f100f4deaf24 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestExecuteInterceptor.java @@ -0,0 +1,44 @@ +package org.skywalking.apm.plugin.spring.resttemplate.sync; + +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, String methodName, 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.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, String methodName, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestRequestInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestRequestInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..ad8b709d3ff4a22748cabb8184258ad2819af10e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestRequestInterceptor.java @@ -0,0 +1,30 @@ +package org.skywalking.apm.plugin.spring.resttemplate.sync; + +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, String methodName, Object[] allArguments, + Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + + } + + @Override public Object afterMethod(EnhancedInstance objInst, String methodName, 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, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestResponseInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestResponseInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..f15bc56e8601a999805d98c9633c1024372682d5 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/RestResponseInterceptor.java @@ -0,0 +1,34 @@ +package org.skywalking.apm.plugin.spring.resttemplate.sync; + +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, String methodName, Object[] allArguments, + Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + + } + + @Override public Object afterMethod(EnhancedInstance objInst, String methodName, 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, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.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.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/sync/define/RestTemplateInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..9fb529bf1a9b98f5ed812253702d74670f9c6e96 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.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.3.x-plugin/src/main/java/org/springframework/http/client/RestRequestInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/springframework/http/client/RestRequestInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..1ce1744c1e0818306a67e8f1af5db4b021531e26 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/springframework/http/client/RestRequestInterceptor.java @@ -0,0 +1,26 @@ +package org.springframework.http.client; + +import java.util.List; +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, String methodName, Object[] allArguments, + Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + + } + + @Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable { + AbstractAsyncClientHttpRequest clientHttpRequest = (AbstractAsyncClientHttpRequest)ret; + clientHttpRequest.getHeaders().set(Config.Plugin.Propagation.HEADER_NAME, String.valueOf(((List)objInst.getSkyWalkingDynamicField()).get(1))); + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 0000000000000000000000000000000000000000..4b5ab45bc500c50fc86f4a46f16b6480658ba587 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,3 @@ +spring-resttemplate-4.3.8=org.skywalking.apm.plugin.spring.resttemplate.async.define.RestTemplateInstrumentation +spring-resttemplate-4.3.8=org.skywalking.apm.plugin.spring.resttemplate.async.define.ResponseExtractorFutureInstrumentation +spring-resttemplate-4.3.8=org.skywalking.apm.plugin.spring.resttemplate.sync.define.RestTemplateInstrumentation