From 015d3877cbc3a04ef46a667873948b0ff3b6a62f Mon Sep 17 00:00:00 2001 From: Daming Date: Thu, 20 May 2021 13:36:13 +0800 Subject: [PATCH] Introduce method interceptor v2 (#6937) --- .github/workflows/plugins-test.1.yaml | 1 + .../AbstractClassEnhancePluginDefine.java | 60 +++++- .../bootstrap/BootstrapInstrumentBoost.java | 100 ++++++++-- .../v2/InstanceMethodInterV2Template.java | 127 +++++++++++++ ...MethodInterV2WithOverrideArgsTemplate.java | 128 +++++++++++++ .../v2/StaticMethodInterV2Template.java | 116 ++++++++++++ ...MethodInterV2WithOverrideArgsTemplate.java | 116 ++++++++++++ .../enhance/ClassEnhancePluginDefine.java | 45 ++--- .../interceptor/enhance/ConstructorInter.java | 2 +- .../v2/ClassEnhancePluginDefineV2.java | 179 ++++++++++++++++++ ...sInstanceMethodsEnhancePluginDefineV2.java | 38 ++++ ...assStaticMethodsEnhancePluginDefineV2.java | 47 +++++ .../enhance/v2/InstMethodsInterV2.java | 85 +++++++++ .../InstMethodsInterV2WithOverrideArgs.java | 105 ++++++++++ .../InstanceMethodsAroundInterceptorV2.java | 54 ++++++ .../enhance/v2/MethodInvocationContext.java | 34 ++++ .../v2/StaticMethodsAroundInterceptorV2.java | 52 +++++ .../enhance/v2/StaticMethodsInterV2.java | 101 ++++++++++ .../StaticMethodsInterV2WithOverrideArgs.java | 101 ++++++++++ .../v2/ConstructorInterceptV2Point.java | 38 ++++ ...claredInstanceMethodsInterceptV2Point.java | 26 +++ .../v2/InstanceMethodsInterceptV2Point.java | 46 +++++ .../v2/StaticMethodsInterceptV2Point.java | 46 +++++ .../apm/plugin/mybatis/Constants.java | 3 + .../plugin/mybatis/MyBatisInterceptor.java | 1 - .../MyBatisShellMethodInterceptor.java | 21 +- .../MyBatisShellMethodInstrumentation.java | 14 +- 27 files changed, 1628 insertions(+), 58 deletions(-) create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java diff --git a/.github/workflows/plugins-test.1.yaml b/.github/workflows/plugins-test.1.yaml index f888d1086a..2c332b57ea 100644 --- a/.github/workflows/plugins-test.1.yaml +++ b/.github/workflows/plugins-test.1.yaml @@ -61,6 +61,7 @@ jobs: - postgresql-above9.4.1207-scenario - mssql-jtds-scenario - mssql-jdbc-scenario + - mybatis-3.x-scenario steps: - uses: actions/checkout@v2 with: diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java index 88c980cf75..5fd3012356 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java @@ -26,6 +26,8 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterc import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; import org.apache.skywalking.apm.agent.core.util.CollectionUtil; import org.apache.skywalking.apm.util.StringUtil; @@ -41,6 +43,11 @@ import java.util.List; public abstract class AbstractClassEnhancePluginDefine { private static final ILog LOGGER = LogManager.getLogger(AbstractClassEnhancePluginDefine.class); + /** + * New field name. + */ + public static final String CONTEXT_ATTR_NAME = "_$EnhancedClassField_ws"; + /** * Main entrance of enhancing the class. * @@ -94,8 +101,43 @@ public abstract class AbstractClassEnhancePluginDefine { return newClassBuilder; } - protected abstract DynamicType.Builder enhance(TypeDescription typeDescription, - DynamicType.Builder newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException; + + /** + * Begin to define how to enhance class. After invoke this method, only means definition is finished. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + protected DynamicType.Builder enhance(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, + ClassLoader classLoader, EnhanceContext context) throws PluginException { + newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader); + + newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context); + + return newClassBuilder; + } + + /** + * Enhance a class to intercept constructors and class instance methods. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + protected abstract DynamicType.Builder enhanceInstance(TypeDescription typeDescription, + DynamicType.Builder newClassBuilder, ClassLoader classLoader, + EnhanceContext context) throws PluginException; + + /** + * Enhance a class to intercept class static methods. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + protected abstract DynamicType.Builder enhanceClass(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, + ClassLoader classLoader) throws PluginException; /** * Define the {@link ClassMatch} for filtering class. @@ -138,10 +180,24 @@ public abstract class AbstractClassEnhancePluginDefine { */ public abstract InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints(); + /** + * Instance methods intercept v2 point. See {@link InstanceMethodsInterceptV2Point} + * + * @return collections of {@link InstanceMethodsInterceptV2Point} + */ + public abstract InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points(); + /** * Static methods intercept point. See {@link StaticMethodsInterceptPoint} * * @return collections of {@link StaticMethodsInterceptPoint} */ public abstract StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints(); + + /** + * Instance methods intercept v2 point. See {@link InstanceMethodsInterceptV2Point} + * + * @return collections of {@link InstanceMethodsInterceptV2Point} + */ + public abstract StaticMethodsInterceptV2Point[] getStaticMethodsInterceptV2Points(); } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java index 19afeeac19..caf5a10b2a 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java @@ -25,6 +25,7 @@ import java.lang.instrument.Instrumentation; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import net.bytebuddy.ByteBuddy; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.description.type.TypeDescription; @@ -42,6 +43,8 @@ import org.apache.skywalking.apm.agent.core.plugin.PluginFinder; import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; import org.apache.skywalking.apm.agent.core.plugin.jdk9module.JDK9ModuleExporter; import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader; @@ -62,7 +65,12 @@ public class BootstrapInstrumentBoost { "org.apache.skywalking.apm.agent.core.plugin.bootstrap.IBootstrapLog", "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance", "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable", - "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult" + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult", + + // interceptor v2 + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.StaticMethodsAroundInterceptorV2", + "org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext", }; private static String INSTANCE_METHOD_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.InstanceMethodInterTemplate"; @@ -71,14 +79,23 @@ public class BootstrapInstrumentBoost { private static String STATIC_METHOD_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.StaticMethodInterTemplate"; private static String STATIC_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.StaticMethodInterWithOverrideArgsTemplate"; + private static String INSTANCE_METHOD_V2_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2.InstanceMethodInterV2Template"; + private static String INSTANCE_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2.InstanceMethodInterV2WithOverrideArgsTemplate"; + private static String STATIC_METHOD_V2_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2.StaticMethodInterV2Template"; + private static String STATIC_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2.StaticMethodInterV2WithOverrideArgsTemplate"; + public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation, AgentBuilder agentBuilder, JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException { - Map classesTypeMap = new HashMap(); + Map classesTypeMap = new HashMap<>(); if (!prepareJREInstrumentation(pluginFinder, classesTypeMap)) { return agentBuilder; } + if (!prepareJREInstrumentationV2(pluginFinder, classesTypeMap)) { + return agentBuilder; + } + for (String highPriorityClass : HIGH_PRIORITY_CLASSES) { loadHighPriorityClass(classesTypeMap, highPriorityClass); } @@ -141,25 +158,76 @@ public class BootstrapInstrumentBoost { TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader()); List bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine(); for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) { - for (InstanceMethodsInterceptPoint point : define.getInstanceMethodsInterceptPoints()) { - if (point.isOverrideArgs()) { - generateDelegator(classesTypeMap, typePool, INSTANCE_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point - .getMethodsInterceptor()); - } else { - generateDelegator(classesTypeMap, typePool, INSTANCE_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor()); + if (Objects.nonNull(define.getInstanceMethodsInterceptPoints())) { + for (InstanceMethodsInterceptPoint point : define.getInstanceMethodsInterceptPoints()) { + if (point.isOverrideArgs()) { + generateDelegator( + classesTypeMap, typePool, INSTANCE_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point + .getMethodsInterceptor()); + } else { + generateDelegator( + classesTypeMap, typePool, INSTANCE_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor()); + } } } - for (ConstructorInterceptPoint point : define.getConstructorsInterceptPoints()) { - generateDelegator(classesTypeMap, typePool, CONSTRUCTOR_DELEGATE_TEMPLATE, point.getConstructorInterceptor()); + if (Objects.nonNull(define.getConstructorsInterceptPoints())) { + for (ConstructorInterceptPoint point : define.getConstructorsInterceptPoints()) { + generateDelegator( + classesTypeMap, typePool, CONSTRUCTOR_DELEGATE_TEMPLATE, point.getConstructorInterceptor()); + } } - for (StaticMethodsInterceptPoint point : define.getStaticMethodsInterceptPoints()) { - if (point.isOverrideArgs()) { - generateDelegator(classesTypeMap, typePool, STATIC_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point - .getMethodsInterceptor()); - } else { - generateDelegator(classesTypeMap, typePool, STATIC_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor()); + if (Objects.nonNull(define.getStaticMethodsInterceptPoints())) { + for (StaticMethodsInterceptPoint point : define.getStaticMethodsInterceptPoints()) { + if (point.isOverrideArgs()) { + generateDelegator( + classesTypeMap, typePool, STATIC_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point + .getMethodsInterceptor()); + } else { + generateDelegator( + classesTypeMap, typePool, STATIC_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor()); + } + } + } + } + return bootstrapClassMatchDefines.size() > 0; + } + + private static boolean prepareJREInstrumentationV2(PluginFinder pluginFinder, + Map classesTypeMap) throws PluginException { + TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader()); + List bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine(); + for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) { + if (Objects.nonNull(define.getInstanceMethodsInterceptV2Points())) { + for (InstanceMethodsInterceptV2Point point : define.getInstanceMethodsInterceptV2Points()) { + if (point.isOverrideArgs()) { + generateDelegator(classesTypeMap, typePool, + INSTANCE_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2() + ); + } else { + generateDelegator( + classesTypeMap, typePool, INSTANCE_METHOD_V2_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2() + ); + } + } + } + + if (Objects.nonNull(define.getStaticMethodsInterceptV2Points())) { + for (StaticMethodsInterceptV2Point point : define.getStaticMethodsInterceptV2Points()) { + if (point.isOverrideArgs()) { + generateDelegator(classesTypeMap, typePool, + STATIC_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2() + ); + } else { + generateDelegator( + classesTypeMap, typePool, STATIC_METHOD_V2_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2() + ); + } } } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java new file mode 100644 index 0000000000..88be482f5f --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import net.bytebuddy.implementation.bind.annotation.This; +import org.apache.skywalking.apm.agent.core.plugin.bootstrap.IBootstrapLog; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class InstanceMethodInterV2Template { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static InstanceMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + if (LOGGER != null) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + } + + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java new file mode 100644 index 0000000000..83fc8a9711 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2; + +import java.lang.reflect.Method; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; +import org.apache.skywalking.apm.agent.core.plugin.bootstrap.IBootstrapLog; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class InstanceMethodInterV2WithOverrideArgsTemplate { + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static InstanceMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Morph OverrideCallable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + if (LOGGER != null) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + } + + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} + diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java new file mode 100644 index 0000000000..74cfb1e26a --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import org.apache.skywalking.apm.agent.core.plugin.bootstrap.IBootstrapLog; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.StaticMethodsAroundInterceptorV2; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class StaticMethodInterV2Template { + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static StaticMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @SuperCall Callable zuper) throws Throwable { + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java new file mode 100644 index 0000000000..09607882d7 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.v2; + +import java.lang.reflect.Method; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import org.apache.skywalking.apm.agent.core.plugin.bootstrap.IBootstrapLog; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.StaticMethodsAroundInterceptorV2; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class StaticMethodInterV2WithOverrideArgsTemplate { + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static StaticMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java index cd7760fd95..81736eea90 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java @@ -38,6 +38,8 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.DeclaredInstanceM import org.apache.skywalking.apm.agent.core.plugin.interceptor.EnhanceException; import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; import org.apache.skywalking.apm.util.StringUtil; import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE; @@ -54,28 +56,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine { private static final ILog LOGGER = LogManager.getLogger(ClassEnhancePluginDefine.class); - /** - * New field name. - */ - public static final String CONTEXT_ATTR_NAME = "_$EnhancedClassField_ws"; - - /** - * Begin to define how to enhance class. After invoke this method, only means definition is finished. - * - * @param typeDescription target class description - * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. - * @return new byte-buddy's builder for further manipulation. - */ - @Override - protected DynamicType.Builder enhance(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, - ClassLoader classLoader, EnhanceContext context) throws PluginException { - newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader); - - newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context); - - return newClassBuilder; - } - /** * Enhance a class to intercept constructors and class instance methods. * @@ -83,7 +63,7 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ - private DynamicType.Builder enhanceInstance(TypeDescription typeDescription, + protected DynamicType.Builder enhanceInstance(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException { ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints(); @@ -194,7 +174,7 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ - private DynamicType.Builder enhanceClass(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, + protected DynamicType.Builder enhanceClass(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, ClassLoader classLoader) throws PluginException { StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints(); String enhanceOriginClassName = typeDescription.getTypeName(); @@ -236,4 +216,21 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi return newClassBuilder; } + + /** + * @return null, means enhance no v2 instance methods. + */ + @Override + public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() { + return null; + } + + /** + * @return null, means enhance no v2 static methods. + */ + @Override + public StaticMethodsInterceptV2Point[] getStaticMethodsInterceptV2Points() { + return null; + } + } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ConstructorInter.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ConstructorInter.java index e9f8f854eb..08c928fb33 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ConstructorInter.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ConstructorInter.java @@ -47,7 +47,7 @@ public class ConstructorInter { try { interceptor = InterceptorInstanceLoader.load(constructorInterceptorClassName, classLoader); } catch (Throwable t) { - throw new PluginException("Can't create InstanceConstructorInterceptor.", t); + throw new PluginException("Can't create InstanceConstructorInterceptorV2.", t); } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java new file mode 100644 index 0000000000..459e15060e --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.implementation.FieldAccessor; +import net.bytebuddy.implementation.MethodDelegation; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; +import org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.EnhanceContext; +import org.apache.skywalking.apm.agent.core.plugin.PluginException; +import org.apache.skywalking.apm.agent.core.plugin.bootstrap.BootstrapInstrumentBoost; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.EnhanceException; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.ConstructorInterceptV2Point; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.DeclaredInstanceMethodsInterceptV2Point; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; +import org.apache.skywalking.apm.util.StringUtil; + +import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE; +import static net.bytebuddy.jar.asm.Opcodes.ACC_VOLATILE; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.not; + +/** + * This class controls all enhance operations, including enhance constructors, instance methods and static methods. All + * the enhances base on three types interceptor point: {@link ConstructorInterceptV2Point}, {@link + * InstanceMethodsInterceptV2Point} and {@link StaticMethodsInterceptV2Point} If plugin is going to enhance constructors, + * instance methods, or both, {@link ClassEnhancePluginDefineV2} will add a field of {@link Object} type. + */ +public abstract class ClassEnhancePluginDefineV2 extends AbstractClassEnhancePluginDefine { + + protected DynamicType.Builder enhanceClass(TypeDescription typeDescription, + DynamicType.Builder newClassBuilder, + ClassLoader classLoader) throws PluginException { + StaticMethodsInterceptV2Point[] staticMethodsInterceptV2Points = getStaticMethodsInterceptV2Points(); + String enhanceOriginClassName = typeDescription.getTypeName(); + if (staticMethodsInterceptV2Points == null || staticMethodsInterceptV2Points.length == 0) { + return newClassBuilder; + } + + for (StaticMethodsInterceptV2Point staticMethodsInterceptV2Point : staticMethodsInterceptV2Points) { + String interceptor = staticMethodsInterceptV2Point.getMethodsInterceptorV2(); + if (StringUtil.isEmpty(interceptor)) { + throw new EnhanceException( + "no StaticMethodsAroundInterceptorV2 define to enhance class " + enhanceOriginClassName); + } + + if (staticMethodsInterceptV2Point.isOverrideArgs()) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(new StaticMethodsInterV2WithOverrideArgs(interceptor))); + } + } else { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(new StaticMethodsInterV2(interceptor))); + } + } + + } + + return newClassBuilder; + } + + protected DynamicType.Builder enhanceInstance(TypeDescription typeDescription, + DynamicType.Builder newClassBuilder, ClassLoader classLoader, + EnhanceContext context) throws PluginException { + InstanceMethodsInterceptV2Point[] instanceMethodsInterceptV2Points = getInstanceMethodsInterceptV2Points(); + String enhanceOriginClassName = typeDescription.getTypeName(); + boolean existedMethodsInterceptV2Points = false; + if (instanceMethodsInterceptV2Points != null && instanceMethodsInterceptV2Points.length > 0) { + existedMethodsInterceptV2Points = true; + } + + if (!existedMethodsInterceptV2Points) { + return newClassBuilder; + } + + if (!typeDescription.isAssignableTo(EnhancedInstance.class)) { + if (!context.isObjectExtended()) { + newClassBuilder = newClassBuilder.defineField( + CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE) + .implement(EnhancedInstance.class) + .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME)); + context.extendObjectCompleted(); + } + } + + if (existedMethodsInterceptV2Points) { + for (InstanceMethodsInterceptV2Point instanceMethodsInterceptV2Point : instanceMethodsInterceptV2Points) { + String interceptor = instanceMethodsInterceptV2Point.getMethodsInterceptorV2(); + if (StringUtil.isEmpty(interceptor)) { + throw new EnhanceException( + "no InstanceMethodsAroundInterceptorV2 define to enhance class " + enhanceOriginClassName); + } + ElementMatcher.Junction junction = not(isStatic()).and( + instanceMethodsInterceptV2Point.getMethodsMatcher()); + if (instanceMethodsInterceptV2Point instanceof DeclaredInstanceMethodsInterceptV2Point) { + junction = junction.and(ElementMatchers.isDeclaredBy(typeDescription)); + } + if (instanceMethodsInterceptV2Point.isOverrideArgs()) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(new InstMethodsInterV2WithOverrideArgs(interceptor, classLoader))); + } + } else { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(new InstMethodsInterV2(interceptor, classLoader))); + } + } + } + } + + return newClassBuilder; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return null; + } + + @Override + public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { + return null; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java new file mode 100644 index 0000000000..71462ff570 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; + +/** + * Plugins, which only need enhance class instance methods. Actually, inherit from {@link + * ClassInstanceMethodsEnhancePluginDefineV2} has no differences with inherit from {@link ClassEnhancePluginDefineV2}. + * Just override {@link ClassEnhancePluginDefineV2#getStaticMethodsInterceptPoints}, and return NULL, which means nothing + * to enhance. + */ +public abstract class ClassInstanceMethodsEnhancePluginDefineV2 extends ClassEnhancePluginDefineV2 { + + /** + * @return null, means enhance no v2 static methods. + */ + @Override + public StaticMethodsInterceptV2Point[] getStaticMethodsInterceptV2Points() { + return null; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java new file mode 100644 index 0000000000..764291810f --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; + +/** + * Plugins, which only need enhance class static methods. Actually, inherit from {@link + * ClassStaticMethodsEnhancePluginDefineV2} has no differences with inherit from {@link ClassEnhancePluginDefineV2}. Just + * override {@link ClassEnhancePluginDefineV2#getConstructorsInterceptPoints} and {@link + * ClassEnhancePluginDefineV2#getInstanceMethodsInterceptV2Points}, and return NULL, which means nothing to enhance. + */ +public abstract class ClassStaticMethodsEnhancePluginDefineV2 extends ClassEnhancePluginDefineV2 { + + /** + * @return null, means enhance no constructors. + */ + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return null; + } + + /** + * @return null, means enhance no v2 instance methods. + */ + @Override + public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() { + return null; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java new file mode 100644 index 0000000000..4afd93cdc3 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import net.bytebuddy.implementation.bind.annotation.This; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.PluginException; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.loader.InterceptorInstanceLoader; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provide a bridge between + * byte-buddy and sky-walking plugin. + */ +public class InstMethodsInterV2 { + private static final ILog LOGGER = LogManager.getLogger(InstMethodsInterV2.class); + + private InstanceMethodsAroundInterceptorV2 interceptor; + + public InstMethodsInterV2(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) { + try { + interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); + } catch (Throwable t) { + throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t); + } + } + + @RuntimeType + public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + return ret; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java new file mode 100644 index 0000000000..72b1311e4c --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import java.lang.reflect.Method; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.PluginException; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable; +import org.apache.skywalking.apm.agent.core.plugin.loader.InterceptorInstanceLoader; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provide a bridge between + * byte-buddy and sky-walking plugin. + */ +public class InstMethodsInterV2WithOverrideArgs { + private static final ILog LOGGER = LogManager.getLogger(InstMethodsInterV2WithOverrideArgs.class); + + /** + * An {@link InstanceMethodsAroundInterceptorV2} This name should only stay in {@link String}, the real {@link Class} + * type will trigger classloader failure. If you want to know more, please check on books about Classloader or + * Classloader appointment mechanism. + */ + private InstanceMethodsAroundInterceptorV2 interceptor; + + /** + * @param instanceMethodsAroundInterceptorClassName class full name. + */ + public InstMethodsInterV2WithOverrideArgs(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) { + try { + interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); + } catch (Throwable t) { + throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t); + } + } + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + return ret; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java new file mode 100644 index 0000000000..e67cc6b60c --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +/** + * A v2 interceptor, which intercept method's invocation. The target methods will be defined in {@link + * ClassEnhancePluginDefineV2}'s subclass, most likely in {@link ClassInstanceMethodsEnhancePluginDefine} + */ +public interface InstanceMethodsAroundInterceptorV2 { + /** + * called before target method invocation. + * + * @param context the method invocation context including result context. + */ + void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInvocationContext context) throws Throwable; + + /** + * called after target method invocation. Even method's invocation triggers an exception. + * + * @param ret the method's original return value. May be null if the method triggers an exception. + * @return the method's actual return value. + */ + Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret, MethodInvocationContext context) throws Throwable; + + /** + * called when occur exception. + * + * @param t the exception occur. + */ + void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t, MethodInvocationContext context); + +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java new file mode 100644 index 0000000000..7916fb9263 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +public class MethodInvocationContext extends MethodInterceptResult { + + private Object context; + + public Object getContext() { + return context; + } + + public void setContext(Object context) { + this.context = context; + } + +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java new file mode 100644 index 0000000000..7600099e4a --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import java.lang.reflect.Method; + +/** + * The static method's interceptor v2 interface. Any plugin, which wants to intercept static methods, must implement this + * interface. + */ +public interface StaticMethodsAroundInterceptorV2 { + /** + * called before target method invocation. + * + * @param context the method invocation context including result context. + */ + void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + MethodInvocationContext context); + + /** + * called after target method invocation. Even method's invocation triggers an exception. + * + * @param ret the method's original return value. + * @return the method's actual return value. + */ + Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Object ret, + MethodInvocationContext context); + + /** + * called when occur exception. + * + * @param t the exception occur. + */ + void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Throwable t, MethodInvocationContext context); +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java new file mode 100644 index 0000000000..641e8edba7 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.loader.InterceptorInstanceLoader; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provide a bridge between + * byte-buddy and sky-walking plugin. + */ +public class StaticMethodsInterV2 { + private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInterV2.class); + + /** + * A class full name, and instanceof {@link StaticMethodsAroundInterceptorV2} This name should only stay in {@link + * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on + * books about Classloader or Classloader appointment mechanism. + */ + private String staticMethodsAroundInterceptorClassName; + + /** + * Set the name of {@link StaticMethodsInterV2#staticMethodsAroundInterceptorClassName} + * + * @param staticMethodsAroundInterceptorClassName class full name. + */ + public StaticMethodsInterV2(String staticMethodsAroundInterceptorClassName) { + this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName; + } + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @SuperCall Callable zuper) throws Throwable { + StaticMethodsAroundInterceptorV2 interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, + clazz.getClassLoader()); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java new file mode 100644 index 0000000000..8e5cb15bc0 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2; + +import java.lang.reflect.Method; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.OverrideCallable; +import org.apache.skywalking.apm.agent.core.plugin.loader.InterceptorInstanceLoader; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provide a bridge between + * byte-buddy and sky-walking plugin. + */ +public class StaticMethodsInterV2WithOverrideArgs { + private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInterV2WithOverrideArgs.class); + + /** + * A class full name, and instanceof {@link StaticMethodsAroundInterceptorV2} This name should only stay in {@link + * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on + * books about Classloader or Classloader appointment mechanism. + */ + private String staticMethodsAroundInterceptorClassName; + + /** + * Set the name of {@link StaticMethodsInterV2WithOverrideArgs#staticMethodsAroundInterceptorClassName} + * + * @param staticMethodsAroundInterceptorClassName class full name. + */ + public StaticMethodsInterV2WithOverrideArgs(String staticMethodsAroundInterceptorClassName) { + this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName; + } + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + StaticMethodsAroundInterceptorV2 interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, + clazz.getClassLoader()); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java new file mode 100644 index 0000000000..dcd0fa30b4 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.v2; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public interface ConstructorInterceptV2Point { + + /** + * Constructor matcher + * + * @return matcher instance. + */ + ElementMatcher getConstructorMatcher(); + + /** + * @return represents a class name, the class instance must be a instance of {@link + * org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor} + */ + String getConstructorInterceptorV2(); + +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java new file mode 100644 index 0000000000..d93e91504b --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.v2; + +/** + * this interface for those who only want to enhance declared method in case of some unexpected issue, such as spring + * controller + */ +public interface DeclaredInstanceMethodsInterceptV2Point extends InstanceMethodsInterceptV2Point { +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java new file mode 100644 index 0000000000..e8932aa35b --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.v2; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; + +/** + * One of the three "Intercept Point". "Intercept Point" is a definition about where and how intercept happens. In this + * "Intercept Point", the definition targets class's instance methods, and the interceptor. + *

+ * ref to two others: {@link ConstructorInterceptPoint} and {@link StaticMethodsInterceptV2Point} + *

+ */ +public interface InstanceMethodsInterceptV2Point { + /** + * class instance methods matcher. + * + * @return methods matcher + */ + ElementMatcher getMethodsMatcher(); + + /** + * @return represents a class name, the class instance must instanceof InstanceMethodsAroundInterceptorV2. + */ + String getMethodsInterceptorV2(); + + boolean isOverrideArgs(); +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java new file mode 100644 index 0000000000..78052a806e --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.plugin.interceptor.v2; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; + +/** + * One of the three "Intercept Point". "Intercept Point" is a definition about where and how intercept happens. In this + * "Intercept Point", the definition targets class's static methods, and the interceptor. + *

+ * ref to two others: {@link ConstructorInterceptPoint} and {@link InstanceMethodsInterceptV2Point} + *

+ */ +public interface StaticMethodsInterceptV2Point { + /** + * static methods matcher. + * + * @return matcher instance. + */ + ElementMatcher getMethodsMatcher(); + + /** + * @return represents a class name, the class instance must instanceof StaticMethodsAroundInterceptorV2. + */ + String getMethodsInterceptorV2(); + + boolean isOverrideArgs(); +} diff --git a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/Constants.java b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/Constants.java index b28e365160..2104ddb109 100644 --- a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/Constants.java +++ b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/Constants.java @@ -21,4 +21,7 @@ package org.apache.skywalking.apm.plugin.mybatis; public class Constants { public static final String MYBATIS_SHELL_METHOD_NAME = "mybatis_shell_method_name"; + + public static final Object COLLECTED_FLAG = new Object(); + } diff --git a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisInterceptor.java b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisInterceptor.java index 160b412271..59fefbf861 100644 --- a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisInterceptor.java +++ b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisInterceptor.java @@ -36,7 +36,6 @@ public class MyBatisInterceptor implements InstanceMethodsAroundInterceptor { String operationName; if (ContextManager.getRuntimeContext().get(Constants.MYBATIS_SHELL_METHOD_NAME) != null) { operationName = String.valueOf(ContextManager.getRuntimeContext().get(Constants.MYBATIS_SHELL_METHOD_NAME)); - ContextManager.getRuntimeContext().remove(Constants.MYBATIS_SHELL_METHOD_NAME); } else { operationName = MethodUtil.generateOperationName(method); } diff --git a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisShellMethodInterceptor.java b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisShellMethodInterceptor.java index e79c0dc3de..7cb15c882c 100644 --- a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisShellMethodInterceptor.java +++ b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/MyBatisShellMethodInterceptor.java @@ -19,18 +19,20 @@ package org.apache.skywalking.apm.plugin.mybatis; import java.lang.reflect.Method; +import java.util.Objects; import org.apache.skywalking.apm.agent.core.context.ContextManager; 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.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; import org.apache.skywalking.apm.agent.core.util.MethodUtil; -public class MyBatisShellMethodInterceptor implements InstanceMethodsAroundInterceptor { +public class MyBatisShellMethodInterceptor implements InstanceMethodsAroundInterceptorV2 { @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInvocationContext context) throws Throwable { if (ContextManager.getRuntimeContext().get(Constants.MYBATIS_SHELL_METHOD_NAME) == null) { + context.setContext(Constants.COLLECTED_FLAG); String operationName = MethodUtil.generateOperationName(method); ContextManager.getRuntimeContext().put(Constants.MYBATIS_SHELL_METHOD_NAME, operationName); } @@ -38,13 +40,18 @@ public class MyBatisShellMethodInterceptor implements InstanceMethodsAroundInter @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, - Object ret) throws Throwable { + Object ret, MethodInvocationContext context) throws Throwable { + if (Objects.nonNull(context.getContext())) { + ContextManager.getRuntimeContext().remove(Constants.MYBATIS_SHELL_METHOD_NAME); + } return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class[] argumentsTypes, Throwable t) { - + Class[] argumentsTypes, Throwable t, MethodInvocationContext context) { + if (Objects.nonNull(context.getContext())) { + ContextManager.getRuntimeContext().remove(Constants.MYBATIS_SHELL_METHOD_NAME); + } } } diff --git a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/define/MyBatisShellMethodInstrumentation.java b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/define/MyBatisShellMethodInstrumentation.java index 6fed1bf812..68a1b232f8 100644 --- a/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/define/MyBatisShellMethodInstrumentation.java +++ b/apm-sniffer/optional-plugins/mybatis-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/mybatis/define/MyBatisShellMethodInstrumentation.java @@ -21,14 +21,14 @@ package org.apache.skywalking.apm.plugin.mybatis.define; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.matcher.ElementMatcher; import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; -import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; -import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; import org.apache.skywalking.apm.plugin.mybatis.MyBatisMethodMatch; import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; -public class MyBatisShellMethodInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { +public class MyBatisShellMethodInstrumentation extends ClassInstanceMethodsEnhancePluginDefineV2 { @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { @@ -36,16 +36,16 @@ public class MyBatisShellMethodInstrumentation extends ClassInstanceMethodsEnhan } @Override - public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { - return new InstanceMethodsInterceptPoint[] { - new InstanceMethodsInterceptPoint() { + public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() { + return new InstanceMethodsInterceptV2Point[] { + new InstanceMethodsInterceptV2Point() { @Override public ElementMatcher getMethodsMatcher() { return MyBatisMethodMatch.INSTANCE.getMyBatisShellMethodMatcher(); } @Override - public String getMethodsInterceptor() { + public String getMethodsInterceptorV2() { return "org.apache.skywalking.apm.plugin.mybatis.MyBatisShellMethodInterceptor"; }