From 137b142aabca61c50362c4e26bdd4e4cb161c21e Mon Sep 17 00:00:00 2001 From: "li.can" Date: Mon, 22 Jul 2019 15:21:59 +0800 Subject: [PATCH] Support servlet 2.5 for Jetty,Tomcat,SpringMvc (#3120) * servlet 2.5 * method exist * update MethodUtil * Update MethodUtil.java Add a comment to the new core util method. @candyleer I am concerning this method will be used widely even unnecessary. --- .../apm/agent/core/util/MethodUtil.java | 41 +++++++++++++++++++ .../jetty/v9/server/HandleInterceptor.java | 12 +++++- .../AbstractMethodInterceptor.java | 11 ++++- .../tomcat78x/TomcatInvokeInterceptor.java | 11 ++++- 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/MethodUtil.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/MethodUtil.java index 80260446e1..cec696e471 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/MethodUtil.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/MethodUtil.java @@ -30,6 +30,7 @@ import java.lang.reflect.Method; public class MethodUtil { + public static String generateOperationName(Method method) { StringBuilder operationName = new StringBuilder(method.getDeclaringClass().getName() + "." + method.getName() + "("); Class[] parameterTypes = method.getParameterTypes(); @@ -42,4 +43,44 @@ public class MethodUtil { operationName.append(")"); return operationName.toString(); } + + /** + * This is a low-performance method, recommand to use this when have to, make sure it is only executed once and the result is being cached. + */ + public static boolean isMethodExist(ClassLoader classLoader, String className, String methodName, String... parameterTypes) { + try { + Class clazz = Class.forName(className, true, classLoader); + if (parameterTypes == null || parameterTypes.length == 0) { + clazz.getDeclaredMethod(methodName); + return true; + } else { + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (Method declaredMethod : declaredMethods) { + if (declaredMethod.getName().equals(methodName) && isParameterTypesEquals(declaredMethod.getParameterTypes(), parameterTypes)) { + return true; + } + } + } + } catch (Exception e) { + //ignore + } + return false; + } + + + private static boolean isParameterTypesEquals(Class[] parameterTypeClazz, String[] parameterTypeString) { + if (parameterTypeClazz == null) { + return false; + } + if (parameterTypeClazz.length != parameterTypeString.length) { + return false; + } + for (int i = 0; i < parameterTypeClazz.length; i++) { + if (!parameterTypeClazz[i].getName().equals(parameterTypeString[i])) { + return false; + } + } + return true; + + } } diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptor.java index 6700cab1de..40e62ca4cb 100644 --- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptor.java @@ -31,10 +31,20 @@ import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.agent.core.util.MethodUtil; import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; import org.eclipse.jetty.server.HttpChannel; public class HandleInterceptor implements InstanceMethodsAroundInterceptor { + + private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST; + private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse"; + private static final String GET_STATUS_METHOD = "getStatus"; + + static { + IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(HandleInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD); + } + @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { @@ -62,7 +72,7 @@ public class HandleInterceptor implements InstanceMethodsAroundInterceptor { HttpChannel httpChannel = (HttpChannel)objInst; HttpServletResponse servletResponse = httpChannel.getResponse(); AbstractSpan span = ContextManager.activeSpan(); - if (servletResponse.getStatus() >= 400) { + if (IS_SERVLET_GET_STATUS_METHOD_EXIST && servletResponse.getStatus() >= 400) { span.errorOccurred(); Tags.STATUS_CODE.set(span, Integer.toString(servletResponse.getStatus())); } diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java index 55306493a0..85734df5bd 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java @@ -46,6 +46,15 @@ import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESP * the abstract method interceptor */ public abstract class AbstractMethodInterceptor implements InstanceMethodsAroundInterceptor { + + private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST; + private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse"; + private static final String GET_STATUS_METHOD = "getStatus"; + + static { + IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(AbstractMethodInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD); + } + public abstract String getRequestURL(Method method); public abstract String getAcceptedMethodTypes(Method method); @@ -151,7 +160,7 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround throw new ServletResponseNotFoundException(); } - if (response.getStatus() >= 400) { + if (IS_SERVLET_GET_STATUS_METHOD_EXIST && response.getStatus() >= 400) { span.errorOccurred(); Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus())); } diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java index 649e5c7126..bb609a92e0 100644 --- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java @@ -32,6 +32,7 @@ import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.agent.core.util.MethodUtil; import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; /** @@ -41,6 +42,14 @@ import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; */ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor { + private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST; + private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse"; + private static final String GET_STATUS_METHOD = "getStatus"; + + static { + IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(TomcatInvokeInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD); + } + /** * * The {@link TraceSegment#refs} of current trace segment will reference to the * trace segment id of the previous level if the serialized context is not null. @@ -76,7 +85,7 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor HttpServletResponse response = (HttpServletResponse)allArguments[1]; AbstractSpan span = ContextManager.activeSpan(); - if (response.getStatus() >= 400) { + if (IS_SERVLET_GET_STATUS_METHOD_EXIST && response.getStatus() >= 400) { span.errorOccurred(); Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus())); } -- GitLab