From ba541e40f965fb8c0f0da0e1830d15bd3aa3e843 Mon Sep 17 00:00:00 2001 From: luanwenfei Date: Tue, 18 Jul 2023 19:08:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=B8=BA=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E5=BC=95=E5=AF=BC=E7=B1=BB=E5=8A=A0=E8=BD=BD=E5=99=A8=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E7=9A=84=E7=B1=BB=E8=80=8C=E5=AE=9A=E5=88=B6=E7=9A=84?= =?UTF-8?q?Template=E3=80=81Transform?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sermant-agentcore/pom.xml | 3 + .../sermant-agentcore-core/pom.xml | 5 + .../sermant/core/AgentCoreEntrance.java | 6 + .../plugin/agent/BufferedAgentBuilder.java | 21 +- .../collector/PluginCollectorManager.java | 205 ++--------- .../agent/template/AdviceConstTemplate.java | 95 ------ .../agent/template/AdviceMemberTemplate.java | 105 ------ .../agent/template/AdviceStaticTemplate.java | 97 ------ .../agent/template/BaseAdviseHandler.java | 202 +++++++++++ .../template/BootstrapConstTemplate.java | 96 ------ .../template/BootstrapMemberTemplate.java | 102 ------ .../template/BootstrapStaticTemplate.java | 100 ------ .../agent/template/CommonBaseAdviser.java | 130 ------- .../agent/template/CommonConstAdviser.java | 95 ------ .../agent/template/CommonMethodAdviser.java | 101 ------ .../plugin/agent/template/DefaultAdviser.java | 75 ++++ .../agent/template/TemplateForCtor.java | 80 +++++ .../agent/template/TemplateForMember.java | 89 +++++ .../agent/template/TemplateForStatic.java | 85 +++++ .../agent/transformer/AdviceTransformer.java | 227 ------------ .../transformer/BootstrapTransformer.java | 323 ------------------ .../agent/transformer/DefaultTransformer.java | 197 +++++++++++ .../sermant/core/utils/ClassUtils.java | 3 +- .../sermant-agentcore-god/pom.xml | 71 ++++ .../agent/adviser/AdviserInterface.java | 47 +++ .../agent/adviser/AdviserScheduler.java | 82 +++++ .../plugin/agent/entity/ExecuteContext.java | 149 ++++---- .../plugin/agent/interceptor/Interceptor.java | 0 .../sermant-agentcore-premain/pom.xml | 2 +- .../{AgentPremain.java => AgentLauncher.java} | 97 ++++-- .../sermant/premain/common/PathDeclarer.java | 9 + 31 files changed, 1132 insertions(+), 1767 deletions(-) delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceConstTemplate.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceMemberTemplate.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceStaticTemplate.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BaseAdviseHandler.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapConstTemplate.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapMemberTemplate.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapStaticTemplate.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonBaseAdviser.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonConstAdviser.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonMethodAdviser.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/DefaultAdviser.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForCtor.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForMember.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForStatic.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/AdviceTransformer.java delete mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/BootstrapTransformer.java create mode 100644 sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/DefaultTransformer.java create mode 100644 sermant-agentcore/sermant-agentcore-god/pom.xml create mode 100644 sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserInterface.java create mode 100644 sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserScheduler.java rename sermant-agentcore/{sermant-agentcore-core => sermant-agentcore-god}/src/main/java/com/huaweicloud/sermant/core/plugin/agent/entity/ExecuteContext.java (90%) rename sermant-agentcore/{sermant-agentcore-core => sermant-agentcore-god}/src/main/java/com/huaweicloud/sermant/core/plugin/agent/interceptor/Interceptor.java (100%) rename sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/{AgentPremain.java => AgentLauncher.java} (59%) diff --git a/sermant-agentcore/pom.xml b/sermant-agentcore/pom.xml index 7c3e5295d8..bb4a3ca4f3 100644 --- a/sermant-agentcore/pom.xml +++ b/sermant-agentcore/pom.xml @@ -46,6 +46,7 @@ true + sermant-agentcore-god sermant-agentcore-core sermant-agentcore-premain sermant-agentcore-config @@ -55,6 +56,7 @@ test + sermant-agentcore-god sermant-agentcore-core sermant-agentcore-premain sermant-agentcore-config @@ -64,6 +66,7 @@ release + sermant-agentcore-god sermant-agentcore-core sermant-agentcore-premain sermant-agentcore-implement diff --git a/sermant-agentcore/sermant-agentcore-core/pom.xml b/sermant-agentcore/sermant-agentcore-core/pom.xml index f48bcd79c7..850f39bc63 100644 --- a/sermant-agentcore/sermant-agentcore-core/pom.xml +++ b/sermant-agentcore/sermant-agentcore-core/pom.xml @@ -93,6 +93,11 @@ + + com.huaweicloud.sermant + sermant-agentcore-god + ${project.version} + net.bytebuddy byte-buddy diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java index 36dacc19e8..ee08c38656 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java @@ -24,6 +24,8 @@ import com.huaweicloud.sermant.core.event.collector.FrameworkEventCollector; import com.huaweicloud.sermant.core.operation.OperationManager; import com.huaweicloud.sermant.core.plugin.PluginSystemEntrance; +import com.huaweicloud.sermant.core.plugin.agent.adviser.AdviserScheduler; +import com.huaweicloud.sermant.core.plugin.agent.template.DefaultAdviser; import com.huaweicloud.sermant.core.service.ServiceManager; import java.lang.instrument.Instrumentation; @@ -72,6 +74,10 @@ public static void run(Map argsMap, Instrumentation instrumentat // 初始化插件 PluginSystemEntrance.initialize(instrumentation); + // 注册Adviser + DefaultAdviser defaultAdviser = new DefaultAdviser(); + AdviserScheduler.registry(defaultAdviser); + // 上报Sermant启动事件 FrameworkEventCollector.getInstance().collectAgentStartEvent(); } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/BufferedAgentBuilder.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/BufferedAgentBuilder.java index e48e344cac..c80b05e257 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/BufferedAgentBuilder.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/BufferedAgentBuilder.java @@ -26,8 +26,8 @@ import com.huaweicloud.sermant.core.plugin.classloader.PluginClassLoader; import com.huaweicloud.sermant.core.utils.FileUtils; -import net.bytebuddy.ByteBuddy; import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.agent.builder.AgentBuilder.Default; import net.bytebuddy.agent.builder.ResettableClassFileTransformer; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeList.Generic; @@ -49,6 +49,7 @@ import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -209,12 +210,10 @@ private BufferedAgentBuilder setOutputListener() { String currentTime = LocalDateTime.now().format(formatter); if (outputPath == null || outputPath.isEmpty()) { outputDirectory = Paths.get(FileUtils.getAgentPath()) - .resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR) - .resolve(currentTime); + .resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR).resolve(currentTime); } else { - outputDirectory = Paths.get(outputPath) - .resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR) - .resolve(currentTime); + outputDirectory = + Paths.get(outputPath).resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR).resolve(currentTime); } final File file; try { @@ -225,13 +224,12 @@ private BufferedAgentBuilder setOutputListener() { } return addAction(builder -> builder.with(new AgentBuilder.Listener.Adapter() { @Override - public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, - JavaModule module, boolean loaded, DynamicType dynamicType) { + public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, + boolean loaded, DynamicType dynamicType) { try { dynamicType.saveIn(file); } catch (IOException e) { - LOGGER.warning(String.format( - "Save class [%s] byte code failed. ", typeDescription.getTypeName())); + LOGGER.log(Level.WARNING, "Save class {0} byte code failed.", typeDescription.getTypeName()); } } })); @@ -274,11 +272,10 @@ public BufferedAgentBuilder addAction(BuilderAction action) { * @return 安装结果,可重置的转换器,若无类元信息改动,调用其reset方法即可重置 */ public ResettableClassFileTransformer install(Instrumentation instrumentation) { - AgentBuilder builder = new AgentBuilder.Default(new ByteBuddy()); + AgentBuilder builder = new Default().disableClassFormatChanges(); for (BuilderAction action : actions) { builder = action.process(builder); } - builder.disableClassFormatChanges(); return builder.installOn(instrumentation); } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/collector/PluginCollectorManager.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/collector/PluginCollectorManager.java index 79a6c1348e..50026d0f19 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/collector/PluginCollectorManager.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/collector/PluginCollectorManager.java @@ -16,29 +16,24 @@ package com.huaweicloud.sermant.core.plugin.agent.collector; +import com.huaweicloud.sermant.core.common.LoggerFactory; import com.huaweicloud.sermant.core.config.ConfigManager; import com.huaweicloud.sermant.core.plugin.agent.config.AgentConfig; import com.huaweicloud.sermant.core.plugin.agent.declarer.AbstractPluginDescription; -import com.huaweicloud.sermant.core.plugin.agent.declarer.InterceptDeclarer; import com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer; import com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDescription; -import com.huaweicloud.sermant.core.plugin.agent.declarer.SuperTypeDeclarer; -import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher; -import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassTypeMatcher; -import com.huaweicloud.sermant.core.plugin.agent.transformer.AdviceTransformer; -import com.huaweicloud.sermant.core.plugin.agent.transformer.BootstrapTransformer; +import com.huaweicloud.sermant.core.plugin.agent.transformer.DefaultTransformer; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.utility.JavaModule; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.ServiceLoader; +import java.util.logging.Level; +import java.util.logging.Logger; /** * 插件收集器管理器,用于从所有插件收集器中获取插件描述器 @@ -48,6 +43,8 @@ * @since 2022-01-26 */ public class PluginCollectorManager { + private static final Logger LOGGER = LoggerFactory.getLogger(); + /** * 通过spi检索所有配置的插件收集器 */ @@ -73,7 +70,7 @@ public static List getPlugins() { */ public static List getPlugins(AgentConfig.CombineStrategy strategy) { final List plugins = new ArrayList<>(); - plugins.addAll(combinePlugins(getDeclarers(), strategy)); + plugins.addAll(combinePlugins(getDeclarers())); plugins.addAll(getDescriptions()); return plugins; } @@ -114,27 +111,12 @@ private static List getDescriptions() { * 合并所有的插件声明器 * * @param declarers 插件声明器列表 - * @param strategy 插件声明器合并策略 * @return 合并所得的插件描述器列表 */ - private static List combinePlugins(List declarers, - AgentConfig.CombineStrategy strategy) { + private static List combinePlugins(List declarers) { final List plugins = new ArrayList<>(); if (!declarers.isEmpty()) { - switch (strategy) { - case NONE: - plugins.addAll(describeDeclarers(declarers)); - break; - case BY_NAME: - plugins.addAll(combineDeclarersByName(declarers)); - break; - case ALL: - plugins.add(combineAllDeclarers(declarers)); - break; - default: - throw new IllegalArgumentException(String.format(Locale.ROOT, - "Unknown combine strategy %s. ", strategy)); - } + plugins.addAll(describeDeclarers(declarers)); } return plugins; } @@ -163,170 +145,25 @@ private static PluginDescription describeDeclarer(PluginDeclarer declarer) { return new AbstractPluginDescription() { @Override public boolean matches(TypeDescription target) { - return declarer.getClassMatcher().matches(target); - } - - @Override - public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDescription, - ClassLoader classLoader, JavaModule module) { - if (classLoader == null) { - return new BootstrapTransformer( - declarer.getInterceptDeclarers(ClassLoader.getSystemClassLoader()) - ).transform(builder, typeDescription, null, module); - } else { - return new AdviceTransformer( - declarer.getInterceptDeclarers(classLoader), declarer.getSuperTypeDeclarers() - ).transform(builder, typeDescription, classLoader, module); - } - } - }; - } - - /** - * 仅通过名称合并插件声明器为一个插件描述器,其他的直接描述{@link #describeDeclarer} - * - * @param declarers 插件声明器集 - * @return 插件描述器集 - */ - private static List combineDeclarersByName(Iterable declarers) { - final List plugins = new ArrayList<>(); - final Map> nameCombinedMap = new HashMap<>(); - for (PluginDeclarer pluginDeclarer : declarers) { - final ClassMatcher classMatcher = pluginDeclarer.getClassMatcher(); - if (classMatcher instanceof ClassTypeMatcher) { - for (String typeName : ((ClassTypeMatcher) classMatcher).getTypeNames()) { - List nameCombinedList = nameCombinedMap.get(typeName); - if (nameCombinedList == null) { - nameCombinedList = new ArrayList<>(); - nameCombinedMap.put(typeName, nameCombinedList); - } - nameCombinedList.add(pluginDeclarer); - } - } else { - plugins.add(describeDeclarer(pluginDeclarer)); - } - } - if (!nameCombinedMap.isEmpty()) { - plugins.add(createNameCombinedDescription(nameCombinedMap)); - } - return plugins; - } - - /** - * 创建根据名称合并插件声明器的插件描述器 - * - * @param nameCombinedMap 插件声明器及其声明的被增强类名集 - * @return 插件描述器 - */ - private static PluginDescription createNameCombinedDescription(Map> nameCombinedMap) { - return new AbstractPluginDescription() { - @Override - public boolean matches(TypeDescription target) { - return nameCombinedMap.containsKey(target.getActualName()); + return matchTarget(declarer.getClassMatcher(), target); } @Override public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDescription, - ClassLoader classLoader, JavaModule module) { - return nameCombinedTransform(builder, typeDescription, classLoader, module, nameCombinedMap); + ClassLoader classLoader, JavaModule module) { + return new DefaultTransformer(declarer.getInterceptDeclarers(ClassLoader.getSystemClassLoader())) + .transform(builder, typeDescription, classLoader, module); } }; } - /** - * 合并所有插件声明器为一个插件描述器 - * - * @param declarers 插件声明器集 - * @return 插件描述器 - */ - private static PluginDescription combineAllDeclarers(Iterable declarers) { - final Map> nameCombinedMap = new HashMap<>(); - final List combinedList = new ArrayList<>(); - for (PluginDeclarer pluginDeclarer : declarers) { - final ClassMatcher classMatcher = pluginDeclarer.getClassMatcher(); - if (classMatcher instanceof ClassTypeMatcher) { - for (String typeName : ((ClassTypeMatcher) classMatcher).getTypeNames()) { - List nameCombinedList = nameCombinedMap.get(typeName); - if (nameCombinedList == null) { - nameCombinedList = new ArrayList<>(); - nameCombinedMap.put(typeName, nameCombinedList); - } - nameCombinedList.add(pluginDeclarer); - } - } else { - combinedList.add(pluginDeclarer); - } - } - return createAllCombinedDescription(nameCombinedMap, combinedList); - } - - /** - * 创建合并全部插件声明器的插件描述器 - * - * @param nameCombinedMap 插件声明器及其声明的被增强类名集 - * @param combinedList 其他模糊匹配的插件声明器列表 - * @return 插件描述器 - */ - private static PluginDescription createAllCombinedDescription(Map> nameCombinedMap, - List combinedList) { - return new AbstractPluginDescription() { - @Override - public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDescription, - ClassLoader classLoader, JavaModule module) { - return nameCombinedTransform(builder, typeDescription, classLoader, module, nameCombinedMap); - } - - @Override - public boolean matches(TypeDescription target) { - final String typeName = target.getActualName(); - for (PluginDeclarer pluginDeclarer : combinedList) { - if (pluginDeclarer.getClassMatcher().matches(target)) { - List declarers = nameCombinedMap.get(typeName); - if (declarers == null) { - declarers = new ArrayList<>(); - nameCombinedMap.put(typeName, declarers); - } - declarers.add(pluginDeclarer); - } - } - return nameCombinedMap.containsKey(typeName); - } - }; - } - - /** - * 处理按名称合并的插件声明器的{@link net.bytebuddy.agent.builder.AgentBuilder.Transformer#transform}方法 - * - * @param builder byte-buddy的动态构建器 - * @param typeDescription 被增强类的描述器 - * @param classLoader 被增强类的类加载器 - * @param module byte-buddy的java模块对象 - * @param nameCombinedMap 插件声明器及其声明的被增强类名集 - * @return 构建器 - */ - private static DynamicType.Builder nameCombinedTransform(DynamicType.Builder builder, - TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, - Map> nameCombinedMap) { - final List pluginDeclarers = nameCombinedMap.remove(typeDescription.getActualName()); - final List interceptDeclarers = new ArrayList<>(); - if (classLoader == null) { - for (PluginDeclarer pluginDeclarer : pluginDeclarers) { - interceptDeclarers.addAll( - Arrays.asList(pluginDeclarer.getInterceptDeclarers(ClassLoader.getSystemClassLoader()))); - } - return new BootstrapTransformer( - interceptDeclarers.toArray(new InterceptDeclarer[0]) - ).transform(builder, typeDescription, null, module); - } else { - final List superTypeDeclarers = new ArrayList<>(); - for (PluginDeclarer pluginDeclarer : pluginDeclarers) { - interceptDeclarers.addAll(Arrays.asList(pluginDeclarer.getInterceptDeclarers(classLoader))); - superTypeDeclarers.addAll(Arrays.asList(pluginDeclarer.getSuperTypeDeclarers())); - } - return new AdviceTransformer( - interceptDeclarers.toArray(new InterceptDeclarer[0]), - superTypeDeclarers.toArray(new SuperTypeDeclarer[0]) - ).transform(builder, typeDescription, classLoader, module); + private static boolean matchTarget(ElementMatcher matcher, TypeDescription target) { + try { + return matcher.matches(target); + } catch (Exception exception) { + LOGGER.log(Level.WARNING, "Exception occurs when math target: " + target.getActualName() + ",{0}", + exception.getMessage()); + return false; } } } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceConstTemplate.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceConstTemplate.java deleted file mode 100644 index 51bda3a998..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceConstTemplate.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; - -import net.bytebuddy.asm.Advice; -import net.bytebuddy.implementation.bytecode.assign.Assigner; - -import java.lang.reflect.Constructor; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -/** - * 构造方法advice模板 - * - * @author HapThorin - * @version 1.0.0 - * @since 2022-01-24 - */ -public class AdviceConstTemplate { - private AdviceConstTemplate() { - } - - /** - * 调用方法的前置触发点 - * - * @param cls 被增强的类 - * @param constructor 构造函数 - * @param methodKey 方法键,用于查找模板类 - * @param arguments 方法入参 - * @param interceptorMap 拦截器集 - * @param extStaticFields 额外静态属性集 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - @Advice.OnMethodEnter - public static void onMethodEnter( - @Advice.Origin Class cls, - @Advice.Origin Constructor constructor, - @Advice.Origin("#t\\##m#s") String methodKey, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.FieldValue(value = "_INTERCEPTOR_MAP_$SERMANT") Map> interceptorMap, - @Advice.FieldValue(value = "_EXT_STATIC_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extStaticFields, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") ExecuteContext context) throws Throwable { - interceptorItr = interceptorMap.get(methodKey).listIterator(); - context = ExecuteContext.forConstructor(cls, constructor, arguments, extStaticFields); - context = CommonConstAdviser.onMethodEnter(context, interceptorItr); - arguments = context.getArguments(); - extStaticFields = context.getExtStaticFields(); - } - - /** - * 调用方法的后置触发点 - * - * @param obj 被增强的对象 - * @param extStaticFields 额外静态属性集 - * @param extMemberFields 额外成员属性集 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - @Advice.OnMethodExit - public static void onMethodExit( - @Advice.This(typing = Assigner.Typing.DYNAMIC) Object obj, - @Advice.FieldValue(value = "_EXT_STATIC_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extStaticFields, - @Advice.FieldValue(value = "_EXT_MEMBER_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extMemberFields, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") ExecuteContext context) throws Throwable { - context = CommonConstAdviser.onMethodExit(context.afterConstructor(obj, extMemberFields), interceptorItr); - extStaticFields = context.getExtStaticFields(); - extMemberFields = context.getExtMemberFields(); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceMemberTemplate.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceMemberTemplate.java deleted file mode 100644 index 21ee1a264c..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceMemberTemplate.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; - -import net.bytebuddy.asm.Advice; -import net.bytebuddy.implementation.bytecode.assign.Assigner; - -import java.lang.reflect.Method; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -/** - * 成员方法advice模板 - * - * @author HapThorin - * @version 1.0.0 - * @since 2022-01-24 - */ -public class AdviceMemberTemplate { - private AdviceMemberTemplate() { - } - - /** - * 调用方法的前置触发点 - * - * @param obj 被增强对象 - * @param method 被增强的方法 - * @param methodKey 方法键,用于查找模板类 - * @param arguments 方法入参 - * @param interceptorMap 拦截器集 - * @param extStaticFields 额外静态属性集 - * @param extMemberFields 额外成员属性集 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @return 是否跳过主要方法 - * @throws Throwable 抛给宿主的异常 - */ - @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) - public static boolean onMethodEnter( - @Advice.This(typing = Assigner.Typing.DYNAMIC) Object obj, - @Advice.Origin Method method, - @Advice.Origin("#t\\##m#s") String methodKey, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.FieldValue(value = "_INTERCEPTOR_MAP_$SERMANT") Map> interceptorMap, - @Advice.FieldValue(value = "_EXT_STATIC_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extStaticFields, - @Advice.FieldValue(value = "_EXT_MEMBER_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extMemberFields, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") ExecuteContext context) throws Throwable { - interceptorItr = interceptorMap.get(methodKey).listIterator(); - context = ExecuteContext.forMemberMethod(obj, method, arguments, extStaticFields, extMemberFields); - context = CommonMethodAdviser.onMethodEnter(context, interceptorItr); - arguments = context.getArguments(); - extStaticFields = context.getExtStaticFields(); - extMemberFields = context.getExtMemberFields(); - return context.isSkip(); - } - - /** - * 调用方法的后置触发点 - * - * @param result 方法调用结果 - * @param throwable 方法调用异常 - * @param extStaticFields 额外静态属性集 - * @param extMemberFields 额外成员属性集 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - @Advice.OnMethodExit(onThrowable = Throwable.class) - public static void onMethodExit( - @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, - @Advice.Thrown Throwable throwable, - @Advice.FieldValue(value = "_EXT_STATIC_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extStaticFields, - @Advice.FieldValue(value = "_EXT_MEMBER_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extMemberFields, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") ExecuteContext context) throws Throwable { - context = context.isSkip() ? context : context.afterMethod(result, throwable); - context = CommonMethodAdviser.onMethodExit(context, interceptorItr); - result = context.getResult(); - extStaticFields = context.getExtStaticFields(); - extMemberFields = context.getExtMemberFields(); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceStaticTemplate.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceStaticTemplate.java deleted file mode 100644 index 7484e419b1..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/AdviceStaticTemplate.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; - -import net.bytebuddy.asm.Advice; -import net.bytebuddy.implementation.bytecode.assign.Assigner; - -import java.lang.reflect.Method; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -/** - * 静态方法advice模板 - * - * @author HapThorin - * @version 1.0.0 - * @since 2022-01-24 - */ -public class AdviceStaticTemplate { - private AdviceStaticTemplate() { - } - - /** - * 调用方法的前置触发点 - * - * @param cls 被增强的类 - * @param method 被增强的方法 - * @param methodKey 方法键,用于查找模板类 - * @param arguments 方法入参 - * @param interceptorMap 拦截器集 - * @param extStaticFields 额外静态属性集 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @return 是否跳过主要方法 - * @throws Throwable 抛给宿主的异常 - */ - @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) - public static boolean onMethodEnter( - @Advice.Origin Class cls, - @Advice.Origin Method method, - @Advice.Origin("#t\\##m#s") String methodKey, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.FieldValue(value = "_INTERCEPTOR_MAP_$SERMANT") Map> interceptorMap, - @Advice.FieldValue(value = "_EXT_STATIC_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extStaticFields, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") ExecuteContext context) throws Throwable { - interceptorItr = interceptorMap.get(methodKey).listIterator(); - context = ExecuteContext.forStaticMethod(cls, method, arguments, extStaticFields); - context = CommonMethodAdviser.onMethodEnter(context, interceptorItr); - arguments = context.getArguments(); - extStaticFields = context.getExtStaticFields(); - return context.isSkip(); - } - - /** - * 调用方法的后置触发点 - * - * @param result 方法调用结果 - * @param throwable 方法调用异常 - * @param extStaticFields 额外静态属性集 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - @Advice.OnMethodExit(onThrowable = Throwable.class) - public static void onMethodExit( - @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, - @Advice.Thrown Throwable throwable, - @Advice.FieldValue(value = "_EXT_STATIC_FIELDS_$SERMANT", - readOnly = false, typing = Assigner.Typing.DYNAMIC) Map extStaticFields, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") ExecuteContext context) throws Throwable { - context = context.isSkip() ? context : context.afterMethod(result, throwable); - context = CommonMethodAdviser.onMethodExit(context, interceptorItr); - result = context.getResult(); - extStaticFields = context.getExtStaticFields(); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BaseAdviseHandler.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BaseAdviseHandler.java new file mode 100644 index 0000000000..4e53e3e714 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BaseAdviseHandler.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; + +import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; + +import java.util.List; +import java.util.ListIterator; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 通用的基础Adviser + * + * @author HapThorin + * @version 1.0.0 + * @since 2022-01-24 + */ +public class BaseAdviseHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + private static final Map> INTERCEPTOR_LIST_MAP = new ConcurrentHashMap<>(); + + private BaseAdviseHandler() { + } + + /** + * 方法入口的Adviser逻辑 + * + * @param context 执行上下文 + * @param adviceKey advice的关键字,由类和方法描述、advice模板、被增强类的类加载器组成 + * @param enterHandler onEnter的异常处理器 + * @return 执行上下文 + * @throws Throwable Throwable + */ + public static ExecuteContext handleMethodEnter(ExecuteContext context, String adviceKey, + ExceptionHandler enterHandler) throws Throwable { + List interceptorList = INTERCEPTOR_LIST_MAP.get(adviceKey); + if (interceptorList == null) { + return context; + } + context.setInterceptorIterator(interceptorList.listIterator()); + return handleMethodEnter(context, context.getInterceptorIterator(), enterHandler); + } + + /** + * onEnter处理逻辑 + * + * @param context 执行上下文 + * @param interceptorItr 拦截器双向迭代器 + * @param enterHandler onEnter的异常处理器 + * @return 执行上下文 + * @throws Throwable 抛给宿主的异常 + */ + public static ExecuteContext handleMethodEnter(ExecuteContext context, ListIterator interceptorItr, + ExceptionHandler enterHandler) throws Throwable { + ExecuteContext newContext = context; + while (interceptorItr.hasNext()) { + try { + final Interceptor interceptor = interceptorItr.next(); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, + String.format(Locale.ROOT, "Method[%s] had been entered, interceptor is [%s].", + MethodKeyCreator.getMethodKey(context.getMethod()), + interceptor.getClass().getName())); + } + try { + final ExecuteContext tempContext = interceptor.before(newContext); + if (tempContext != null) { + newContext = tempContext; + } + if (newContext.isSkip()) { + return newContext; + } + } catch (Throwable t) { + enterHandler.handle(context, interceptor, t); + } + } catch (Exception exception) { + LOGGER.log(Level.SEVERE, "Exception occurs when method enter.", exception); + return newContext; + } + + // 指定向宿主应用抛出异常 + if (newContext.getThrowableOut() != null) { + throw newContext.getThrowableOut(); + } + } + return newContext; + } + + /** + * 方法出口的Adviser逻辑 + * + * @param context 执行上下文 + * @param adviceKey advice的关键字,由类和方法描述、advice模板、被增强类的类加载器组成 + * @param throwHandler onThrow的异常处理器 + * @param exitHandler onExit的异常处理器 + * @return 执行上下文 + * @throws Throwable Throwable + */ + public static ExecuteContext handleMethodExit(ExecuteContext context, String adviceKey, + ExceptionHandler throwHandler, ExceptionHandler exitHandler) throws Throwable { + List interceptorList = INTERCEPTOR_LIST_MAP.get(adviceKey); + if (interceptorList == null) { + return context; + } + return handleMethodExit(context, context.getInterceptorIterator(), throwHandler, exitHandler); + } + + /** + * onExit&onThrow的处理逻辑 + * + * @param context 执行上下文 + * @param interceptorItr 拦截器双向迭代器 + * @param throwHandler onThrow的异常处理器 + * @param exitHandler onExit的异常处理器 + * @return 执行上下文 + * @throws Throwable 抛给宿主的异常 + */ + public static ExecuteContext handleMethodExit(ExecuteContext context, ListIterator interceptorItr, + ExceptionHandler throwHandler, ExceptionHandler exitHandler) throws Throwable { + ExecuteContext newContext = context; + while (interceptorItr.hasPrevious()) { + try { + final Interceptor interceptor = interceptorItr.previous(); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, + String.format(Locale.ROOT, "Method[%s] had been exited, interceptor is [%s].", + MethodKeyCreator.getMethodKey(context.getMethod()), + interceptor.getClass().getName())); + } + if (newContext.getThrowable() != null && throwHandler != null) { + try { + final ExecuteContext tempContext = interceptor.onThrow(newContext); + if (tempContext != null) { + newContext = tempContext; + } + } catch (Throwable t) { + throwHandler.handle(newContext, interceptor, t); + } + if (newContext.getThrowableOut() != null) { + throw newContext.getThrowableOut(); + } + } + try { + final ExecuteContext tempContext = interceptor.after(newContext); + if (tempContext != null) { + newContext = tempContext; + } + } catch (Throwable t) { + exitHandler.handle(newContext, interceptor, t); + } + } catch (Exception exception) { + LOGGER.log(Level.SEVERE, "Exception occurs when method exit.", exception); + return newContext; + } + if (newContext.getThrowableOut() != null) { + throw newContext.getThrowableOut(); + } + } + return newContext; + } + + public static Map> getInterceptorListMap() { + return INTERCEPTOR_LIST_MAP; + } + + /** + * 异常处理器接口 + * + * @since 2022-01-24 + */ + public interface ExceptionHandler { + /** + * 异常处理逻辑 + * + * @param context 执行上下文 + * @param interceptor 拦截器 + * @param throwable 抛出的异常 + */ + void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapConstTemplate.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapConstTemplate.java deleted file mode 100644 index db3ab9ebed..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapConstTemplate.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2021-2021 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.plugin.agent.transformer.BootstrapTransformer; - -import net.bytebuddy.asm.Advice; -import net.bytebuddy.implementation.bytecode.assign.Assigner; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; - -/** - * 启动类构造函数advice模板 - *

启动类加载器加载类的构造函数如果需要增强,则需要使用该模板 - * - * @author HapThorin - * @version 1.0.0 - * @since 2021-10-27 - */ -public class BootstrapConstTemplate { - private BootstrapConstTemplate() { - } - - /** - * 调用方法的前置触发点 - * - * @param cls 被增强的类 - * @param constructor 构造函数 - * @param methodKey 方法键,用于查找模板类 - * @param arguments 方法入参 - * @param interceptorItr 拦截器迭代器 - * @param methodsMap ExecuteContext和CommonMethodAdviser中部方法的反射缓存 - * @param context 执行上下文 - * @throws Exception 执行异常 - */ - @Advice.OnMethodEnter - public static void onMethodEnter( - @Advice.Origin Class cls, - @Advice.Origin Constructor constructor, - @Advice.Origin("#t\\##m#s") String methodKey, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.Local(value = "_METHODS_MAP_$SERMANT_LOCAL") HashMap methodsMap, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context - ) throws Exception { - final ClassLoader loader = ClassLoader.getSystemClassLoader(); - final String adviceClsName = "com.huaweicloud.sermant.core.plugin.agent.template.BootstrapConstTemplate_" - + Integer.toHexString(methodKey.hashCode()); - final Class templateCls = loader.loadClass(adviceClsName); - interceptorItr = ((List)templateCls.getDeclaredField(BootstrapTransformer.INTERCEPTORS_FIELD_NAME).get(null)) - .listIterator(); - methodsMap = - (HashMap)templateCls.getDeclaredField(BootstrapTransformer.METHODS_MAP_NAME).get(null); - context = methodsMap.get("forConstructor").invoke(null, cls, constructor, arguments, null); - context = methodsMap.get("onMethodEnter").invoke(null, context, interceptorItr); - arguments = (Object[])methodsMap.get("getArguments").invoke(context); - } - - /** - * 调用方法的后置触发点 - * - * @param obj 被增强的对象 - * @param interceptorItr 拦截器迭代器 - * @param methodsMap ExecuteContext和CommonMethodAdviser中部方法的反射缓存 - * @param context 执行上下文 - * @throws Exception 执行异常 - */ - @Advice.OnMethodExit - public static void onMethodExit( - @Advice.This(typing = Assigner.Typing.DYNAMIC) Object obj, - @Advice.Local(value = "_METHODS_MAP_$SERMANT_LOCAL") HashMap methodsMap, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context - ) throws Exception { - context = methodsMap.get("afterConstructor").invoke(context, obj, null); - methodsMap.get("onMethodExit").invoke(null, context, interceptorItr); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapMemberTemplate.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapMemberTemplate.java deleted file mode 100644 index dd93735820..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapMemberTemplate.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2021-2021 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.plugin.agent.transformer.BootstrapTransformer; - -import net.bytebuddy.asm.Advice; -import net.bytebuddy.implementation.bytecode.assign.Assigner; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; - -/** - * 启动类实例方法advice模板 - *

启动类加载器加载类的实例方法如果需要增强,则需要使用该模板 - * - * @author HapThorin - * @version 1.0.0 - * @since 2021-10-27 - */ -public class BootstrapMemberTemplate { - private BootstrapMemberTemplate() { - } - - /** - * 调用方法的前置触发点 - * - * @param obj 被增强的对象 - * @param method 被增强的方法 - * @param methodKey 方法键,用于查找模板类 - * @param arguments 方法入参 - * @param methodsMap ExecuteContext和CommonMethodAdviser中部方法的反射缓存 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @param isSkip 是否跳过主流程 - * @return 是否跳过主要方法 - * @throws Exception 执行异常 - */ - @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) - public static boolean onMethodEnter(@Advice.This(typing = Assigner.Typing.DYNAMIC) Object obj, - @Advice.Origin Method method, @Advice.Origin("#t\\##m#s") String methodKey, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.Local(value = "_METHODS_MAP_$SERMANT_LOCAL") HashMap methodsMap, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, - @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip - - ) throws Exception { - final ClassLoader loader = ClassLoader.getSystemClassLoader(); - final String adviceClsName = "com.huaweicloud.sermant.core.plugin.agent.template.BootstrapMemberTemplate_" - + Integer.toHexString(methodKey.hashCode()); - final Class templateCls = loader.loadClass(adviceClsName); - interceptorItr = ((List)templateCls.getDeclaredField(BootstrapTransformer.INTERCEPTORS_FIELD_NAME).get(null)) - .listIterator(); - methodsMap = - (HashMap)templateCls.getDeclaredField(BootstrapTransformer.METHODS_MAP_NAME).get(null); - context = methodsMap.get("forMemberMethod").invoke(null, obj, method, arguments, null, null); - context = methodsMap.get("onMethodEnter").invoke(null, context, interceptorItr); - arguments = (Object[])methodsMap.get("getArguments").invoke(context); - isSkip = (Boolean)methodsMap.get("isSkip").invoke(context); - return isSkip; - } - - /** - * 调用方法的后置触发点 - * - * @param result 方法调用结果 - * @param throwable 方法调用异常 - * @param methodsMap ExecuteContext和CommonMethodAdviser中部方法的反射缓存 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @param isSkip 是否跳过主流程 - * @throws Exception 执行异常 - */ - @Advice.OnMethodExit(onThrowable = Throwable.class) - public static void onMethodExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, - @Advice.Thrown Throwable throwable, - @Advice.Local(value = "_METHODS_MAP_$SERMANT_LOCAL") HashMap methodsMap, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, - @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip) throws Exception { - context = isSkip ? context : methodsMap.get("afterMethod").invoke(context, result, throwable); - context = methodsMap.get("onMethodExit").invoke(null, context, interceptorItr); - result = methodsMap.get("getResult").invoke(context); - } -} \ No newline at end of file diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapStaticTemplate.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapStaticTemplate.java deleted file mode 100644 index 4c28ed08b7..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/BootstrapStaticTemplate.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2021-2021 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.plugin.agent.transformer.BootstrapTransformer; - -import net.bytebuddy.asm.Advice; -import net.bytebuddy.implementation.bytecode.assign.Assigner; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; - -/** - * 启动类静态方法advice模板 - *

启动类加载器加载类的静态方法如果需要增强,则需要使用该模板 - * - * @author HapThorin - * @version 1.0.0 - * @since 2021-10-27 - */ -public class BootstrapStaticTemplate { - private BootstrapStaticTemplate() { - } - - /** - * 调用方法的前置触发点 - * - * @param cls 被增强的类 - * @param method 被增强的方法 - * @param methodKey 方法键,用于查找模板类 - * @param arguments 方法入参 - * @param methodsMap ExecuteContext和CommonMethodAdviser中部方法的反射缓存 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @param isSkip 是否跳过主流程 - * @return 是否跳过主要方法 - * @throws Exception 执行异常 - */ - @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) - public static boolean onMethodEnter(@Advice.Origin Class cls, @Advice.Origin Method method, - @Advice.Origin("#t\\##m#s") String methodKey, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.Local(value = "_METHODS_MAP_$SERMANT_LOCAL") HashMap methodsMap, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, - @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip) throws Exception { - final ClassLoader loader = ClassLoader.getSystemClassLoader(); - final String adviceClsName = "com.huaweicloud.sermant.core.plugin.agent.template.BootstrapStaticTemplate_" - + Integer.toHexString(methodKey.hashCode()); - final Class templateCls = loader.loadClass(adviceClsName); - interceptorItr = ((List)templateCls.getDeclaredField(BootstrapTransformer.INTERCEPTORS_FIELD_NAME).get(null)) - .listIterator(); - methodsMap = - (HashMap)templateCls.getDeclaredField(BootstrapTransformer.METHODS_MAP_NAME).get(null); - context = methodsMap.get("forStaticMethod").invoke(null, cls, method, arguments, null); - context = methodsMap.get("onMethodEnter").invoke(null, context, interceptorItr); - arguments = (Object[])methodsMap.get("getArguments").invoke(context); - isSkip = (Boolean)methodsMap.get("isSkip").invoke(context); - return isSkip; - } - - /** - * 调用方法的后置触发点 - * - * @param result 方法调用结果 - * @param throwable 方法调用异常 - * @param methodsMap ExecuteContext和CommonMethodAdviser中部方法的反射缓存 - * @param interceptorItr 拦截器迭代器 - * @param context 执行上下文 - * @param isSkip 是否跳过主流程 - * @throws Exception 执行异常 - */ - @Advice.OnMethodExit(onThrowable = Throwable.class) - public static void onMethodExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, - @Advice.Thrown Throwable throwable, - @Advice.Local(value = "_METHODS_MAP_$SERMANT_LOCAL") HashMap methodsMap, - @Advice.Local(value = "_INTERCEPTOR_ITR_$SERMANT_LOCAL") ListIterator interceptorItr, - @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, - @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip) throws Exception { - context = isSkip ? context : methodsMap.get("afterMethod").invoke(context, result, throwable); - context = methodsMap.get("onMethodExit").invoke(null, context, interceptorItr); - result = methodsMap.get("getResult").invoke(context); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonBaseAdviser.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonBaseAdviser.java deleted file mode 100644 index 1f30dab30e..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonBaseAdviser.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.common.LoggerFactory; -import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; - -import java.util.ListIterator; -import java.util.Locale; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * 通用的基础Adviser - * - * @author HapThorin - * @version 1.0.0 - * @since 2022-01-24 - */ -public class CommonBaseAdviser { - private static final Logger LOGGER = LoggerFactory.getLogger(); - - private CommonBaseAdviser() { - } - - /** - * 前置触发点 - * - * @param context 执行上下文 - * @param interceptorItr 拦截器双向迭代器 - * @param beforeHandler before的异常处理器 - * @return 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - public static ExecuteContext onMethodEnter(ExecuteContext context, ListIterator interceptorItr, - ExceptionHandler beforeHandler) throws Throwable { - ExecuteContext newContext = context; - while (interceptorItr.hasNext()) { - final Interceptor interceptor = interceptorItr.next(); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, String.format(Locale.ROOT, "Method[%s] had been entered, interceptor is [%s].", - MethodKeyCreator.getMethodKey(context.getMethod()), interceptor.getClass().getName())); - } - try { - final ExecuteContext tempContext = interceptor.before(newContext); - if (tempContext != null) { - newContext = tempContext; - } - if (newContext.isSkip()) { - return newContext; - } - } catch (Throwable t) { - beforeHandler.handle(context, interceptor, t); - } - if (newContext.getThrowableOut() != null) { - throw newContext.getThrowableOut(); - } - } - return newContext; - } - - /** - * 后置触发点 - * - * @param context 执行上下文 - * @param interceptorItr 拦截器双向迭代器 - * @param onThrowHandler onThrow的异常处理器 - * @param afterHandler after的的异常处理器 - * @return 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - public static ExecuteContext onMethodExit(ExecuteContext context, ListIterator interceptorItr, - ExceptionHandler onThrowHandler, ExceptionHandler afterHandler) throws Throwable { - ExecuteContext newContext = context; - while (interceptorItr.hasPrevious()) { - final Interceptor interceptor = interceptorItr.previous(); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, String.format(Locale.ROOT, "Method[%s] had been exited, interceptor is [%s].", - MethodKeyCreator.getMethodKey(context.getMethod()), interceptor.getClass().getName())); - } - if (newContext.getThrowable() != null && onThrowHandler != null) { - try { - final ExecuteContext tempContext = interceptor.onThrow(newContext); - if (tempContext != null) { - newContext = tempContext; - } - } catch (Throwable t) { - onThrowHandler.handle(newContext, interceptor, t); - } - if (newContext.getThrowableOut() != null) { - throw newContext.getThrowableOut(); - } - } - try { - final ExecuteContext tempContext = interceptor.after(newContext); - if (tempContext != null) { - newContext = tempContext; - } - } catch (Throwable t) { - afterHandler.handle(newContext, interceptor, t); - } - if (newContext.getThrowableOut() != null) { - throw newContext.getThrowableOut(); - } - } - return newContext; - } - - /** - * 异常处理器 - */ - public interface ExceptionHandler { - void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonConstAdviser.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonConstAdviser.java deleted file mode 100644 index 2a8b716109..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonConstAdviser.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.common.LoggerFactory; -import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; - -import java.util.ListIterator; -import java.util.Locale; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * 通用的构造方法Adviser - * - * @author HapThorin - * @version 1.0.0 - * @since 2022-01-24 - */ -public class CommonConstAdviser { - /** - * 日志 - */ - private static final Logger LOGGER = LoggerFactory.getLogger(); - - private CommonConstAdviser() { - } - - /** - * 输出错误日志 - * - * @param scene 场景 - * @param context 执行上下文 - * @param interceptor 拦截器对象 - * @param throwable 错误对象 - */ - private static void logError(String scene, ExecuteContext context, Interceptor interceptor, Throwable throwable) { - LOGGER.log(Level.SEVERE, String.format(Locale.ROOT, "An error occurred %s [%s] in interceptor [%s]: ", - scene, MethodKeyCreator.getConstKey(context.getConstructor()), interceptor.getClass().getName()), - throwable); - } - - /** - * 调用构造函数的前置触发点 - * - * @param context 执行上下文 - * @param interceptorItr 拦截器双向迭代器 - * @return 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - public static ExecuteContext onMethodEnter(ExecuteContext context, ListIterator interceptorItr) - throws Throwable { - return CommonBaseAdviser.onMethodEnter(context, interceptorItr, - new CommonBaseAdviser.ExceptionHandler() { - @Override - public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { - logError("before initialize", context, interceptor, throwable); - } - }); - } - - /** - * 调用构造函数的后置触发点 - * - * @param context 执行上下文 - * @param interceptorItr 拦截器双向迭代器 - * @return 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - public static ExecuteContext onMethodExit(ExecuteContext context, ListIterator interceptorItr) - throws Throwable { - return CommonBaseAdviser.onMethodExit(context, interceptorItr, null, - new CommonBaseAdviser.ExceptionHandler() { - @Override - public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { - logError("after initialize", context, interceptor, throwable); - } - }); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonMethodAdviser.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonMethodAdviser.java deleted file mode 100644 index 3724811dd5..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/CommonMethodAdviser.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; - -import com.huaweicloud.sermant.core.common.LoggerFactory; -import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; - -import java.util.ListIterator; -import java.util.Locale; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * 通用的方法Adviser - * - * @author HapThorin - * @version 1.0.0 - * @since 2022-01-24 - */ -public class CommonMethodAdviser { - /** - * 日志 - */ - private static final Logger LOGGER = LoggerFactory.getLogger(); - - private CommonMethodAdviser() { - } - - /** - * 输出错误日志 - * - * @param scene 场景 - * @param context 执行上下文 - * @param interceptor 拦截器对象 - * @param throwable 错误对象 - */ - private static void logError(String scene, ExecuteContext context, Interceptor interceptor, Throwable throwable) { - LOGGER.log(Level.SEVERE, String.format(Locale.ROOT, "An error occurred %s [%s] in interceptor [%s]: ", - scene, MethodKeyCreator.getMethodKey(context.getMethod()), interceptor.getClass().getName()), - throwable); - } - - /** - * 调用方法的前置触发点 - * - * @param context 执行上下文 - * @param interceptorItr 拦截器双向迭代器 - * @return 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - public static ExecuteContext onMethodEnter(ExecuteContext context, ListIterator interceptorItr) - throws Throwable { - return CommonBaseAdviser.onMethodEnter(context, interceptorItr, - new CommonBaseAdviser.ExceptionHandler() { - @Override - public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { - logError("before executing", context, interceptor, throwable); - } - }); - } - - /** - * 调用方法的后置触发点 - * - * @param context 执行上下文 - * @param interceptorItr 拦截器双向迭代器 - * @return 执行上下文 - * @throws Throwable 抛给宿主的异常 - */ - public static ExecuteContext onMethodExit(ExecuteContext context, ListIterator interceptorItr) - throws Throwable { - return CommonBaseAdviser.onMethodExit(context, interceptorItr, - new CommonBaseAdviser.ExceptionHandler() { - @Override - public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { - logError("while handling error from", context, interceptor, throwable); - } - }, - new CommonBaseAdviser.ExceptionHandler() { - @Override - public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { - logError("after executing", context, interceptor, throwable); - } - }); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/DefaultAdviser.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/DefaultAdviser.java new file mode 100644 index 0000000000..fb6c22ce80 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/DefaultAdviser.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; + +import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.core.plugin.agent.adviser.AdviserInterface; +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; + +import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 通用的方法Adviser + * + * @author HapThorin + * @version 1.0.0 + * @since 2022-01-24 + */ +public class DefaultAdviser implements AdviserInterface { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + /** + * 输出错误日志 + * + * @param scene 场景 + * @param context 执行上下文 + * @param interceptor 拦截器对象 + * @param throwable 错误对象 + */ + private void logError(String scene, ExecuteContext context, Interceptor interceptor, Throwable throwable) { + LOGGER.log(Level.SEVERE, String.format(Locale.ROOT, "An error occurred %s [%s] in interceptor [%s]: ", scene, + MethodKeyCreator.getMethodKey(context.getMethod()), interceptor.getClass().getName()), throwable); + } + + @Override + public ExecuteContext onMethodEnter(ExecuteContext context, String adviceKey) throws Throwable { + return BaseAdviseHandler.handleMethodEnter(context, adviceKey, new BaseAdviseHandler.ExceptionHandler() { + @Override + public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { + logError("before executing", context, interceptor, throwable); + } + }); + } + + @Override + public ExecuteContext onMethodExit(ExecuteContext context, String adviceKey) throws Throwable { + return BaseAdviseHandler.handleMethodExit(context, adviceKey, new BaseAdviseHandler.ExceptionHandler() { + @Override + public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { + logError("while handling error from", context, interceptor, throwable); + } + }, new BaseAdviseHandler.ExceptionHandler() { + @Override + public void handle(ExecuteContext context, Interceptor interceptor, Throwable throwable) { + logError("after executing", context, interceptor, throwable); + } + }); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForCtor.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForCtor.java new file mode 100644 index 0000000000..ab8f0003a5 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForCtor.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; + +import com.huaweicloud.sermant.core.plugin.agent.adviser.AdviserScheduler; +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; + +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Constructor; + +/** + * 构造方法advice模板 + * + * @author luanwenfei + * @since 2023-07-18 + */ +public class TemplateForCtor { + private TemplateForCtor() { + } + + /** + * 调用方法的前置触发点 + * + * @param cls 被增强的类 + * @param constructor 构造函数 + * @param methodKey 方法键,用于查找模板类 + * @param arguments 方法入参 + * @param adviceKey advice类名 + * @param context 执行上下文 + * @throws Throwable 执行异常 + */ + @Advice.OnMethodEnter + public static void onMethodEnter( + @Advice.Origin Class cls, + @Advice.Origin Constructor constructor, + @Advice.Origin("#t\\##m#s") String methodKey, + @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Local(value = "_ADVICE_KEY_$SERMANT_LOCAL") String adviceKey, + @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context + ) throws Throwable { + adviceKey = "TemplateForCtor_" + Integer.toHexString(methodKey.hashCode()) + "_" + cls.getClassLoader(); + context = ExecuteContext.forConstructor(cls, constructor, arguments, null); + context = AdviserScheduler.onMethodEnter(context, adviceKey); + arguments = ((ExecuteContext) context).getArguments(); + } + + /** + * 调用方法的后置触发点 + * + * @param obj 被增强的对象 + * @param adviceKey advice类名 + * @param context 执行上下文 + * @throws Throwable 执行异常 + */ + @Advice.OnMethodExit + public static void onMethodExit( + @Advice.This(typing = Assigner.Typing.DYNAMIC) Object obj, + @Advice.Local(value = "_ADVICE_KEY_$SERMANT_LOCAL") String adviceKey, + @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context + ) throws Throwable { + context = ((ExecuteContext) context).afterConstructor(obj,null); + AdviserScheduler.onMethodExit(context, adviceKey); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForMember.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForMember.java new file mode 100644 index 0000000000..5b7be87fdd --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForMember.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; + +import com.huaweicloud.sermant.core.plugin.agent.adviser.AdviserScheduler; +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; + +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * 实例方法advice模板 + * + * @author luanwenfei + * @since 2023-07-18 + */ +public class TemplateForMember { + private TemplateForMember() { + } + + /** + * 调用方法的前置触发点 + * + * @param cls 被增强的类 + * @param obj 被增强的对象 + * @param method 被增强的方法 + * @param methodKey 方法键,用于查找模板类 + * @param arguments 方法入参 + * @param adviceKey advice类名 + * @param context 执行上下文 + * @param isSkip 是否跳过主流程 + * @return 是否跳过主要方法 + * @throws Throwable 执行异常 + */ + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + public static boolean onMethodEnter(@Advice.Origin Class cls, + @Advice.This(typing = Assigner.Typing.DYNAMIC) Object obj, + @Advice.Origin Method method, @Advice.Origin("#t\\##m#s") String methodKey, + @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Local(value = "_ADVICE_KEY_$SERMANT_LOCAL") String adviceKey, + @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, + @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip + + ) throws Throwable { + adviceKey = "TemplateForMember_" + Integer.toHexString(methodKey.hashCode()) + "_" + cls.getClassLoader(); + context = ExecuteContext.forMemberMethod(obj, method, arguments, null, null); + context = AdviserScheduler.onMethodEnter(context, adviceKey); + arguments = ((ExecuteContext) context).getArguments(); + isSkip = ((ExecuteContext) context).isSkip(); + return isSkip; + } + + /** + * 调用方法的后置触发点 + * + * @param result 方法调用结果 + * @param throwable 方法调用异常 + * @param adviceKey advice类名 + * @param context 执行上下文 + * @param isSkip 是否跳过主流程 + * @throws Throwable 执行异常 + */ + @Advice.OnMethodExit(onThrowable = Throwable.class) + public static void onMethodExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local(value = "_ADVICE_KEY_$SERMANT_LOCAL") String adviceKey, + @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, + @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip) throws Throwable { + context = isSkip ? context : ((ExecuteContext) context).afterMethod(result, throwable); + context = AdviserScheduler.onMethodExit(context, adviceKey); + result = ((ExecuteContext) context).getResult(); + } +} \ No newline at end of file diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForStatic.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForStatic.java new file mode 100644 index 0000000000..4337603c16 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/template/TemplateForStatic.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.template; + +import com.huaweicloud.sermant.core.plugin.agent.adviser.AdviserScheduler; +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; + +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * 静态方法advice模板 + * + * @author luanwenfei + * @since 2023-07-18 + */ +public class TemplateForStatic { + private TemplateForStatic() { + } + + /** + * 调用方法的前置触发点 + * + * @param cls 被增强的类 + * @param method 被增强的方法 + * @param methodKey 方法键,用于查找模板类 + * @param arguments 方法入参 + * @param adviceKey advice类名 + * @param context 执行上下文 + * @param isSkip 是否跳过主流程 + * @return 是否跳过主要方法 + * @throws Throwable 执行异常 + */ + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + public static boolean onMethodEnter(@Advice.Origin Class cls, @Advice.Origin Method method, + @Advice.Origin("#t\\##m#s") String methodKey, + @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Local(value = "_ADVICE_KEY_$SERMANT_LOCAL") String adviceKey, + @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, + @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip) throws Throwable { + adviceKey = "TemplateForStatic_" + Integer.toHexString(methodKey.hashCode()) + "_" + cls.getClassLoader(); + context = ExecuteContext.forStaticMethod(cls, method, arguments, null); + context = AdviserScheduler.onMethodEnter(context, adviceKey); + arguments = ((ExecuteContext) context).getArguments(); + isSkip = ((ExecuteContext) context).isSkip(); + return isSkip; + } + + /** + * 调用方法的后置触发点 + * + * @param result 方法调用结果 + * @param throwable 方法调用异常 + * @param adviceKey advice类名 + * @param context 执行上下文 + * @param isSkip 是否跳过主流程 + * @throws Throwable 执行异常 + */ + @Advice.OnMethodExit(onThrowable = Throwable.class) + public static void onMethodExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Thrown Throwable throwable, + @Advice.Local(value = "_ADVICE_KEY_$SERMANT_LOCAL") String adviceKey, + @Advice.Local(value = "_EXECUTE_CONTEXT_$SERMANT_LOCAL") Object context, + @Advice.Local(value = "_IS_SKIP_$SERMANT_LOCAL") Boolean isSkip) throws Throwable { + context = isSkip ? context : ((ExecuteContext) context).afterMethod(result, throwable); + context = AdviserScheduler.onMethodExit(context, adviceKey); + result = ((ExecuteContext) context).getResult(); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/AdviceTransformer.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/AdviceTransformer.java deleted file mode 100644 index ff265414e1..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/AdviceTransformer.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.transformer; - -import com.huaweicloud.sermant.core.plugin.agent.declarer.InterceptDeclarer; -import com.huaweicloud.sermant.core.plugin.agent.declarer.SuperTypeDeclarer; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; -import com.huaweicloud.sermant.core.plugin.agent.template.AdviceConstTemplate; -import com.huaweicloud.sermant.core.plugin.agent.template.AdviceMemberTemplate; -import com.huaweicloud.sermant.core.plugin.agent.template.AdviceStaticTemplate; -import com.huaweicloud.sermant.core.plugin.agent.template.MethodKeyCreator; - -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.modifier.Ownership; -import net.bytebuddy.description.modifier.Visibility; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.implementation.LoadedTypeInitializer; -import net.bytebuddy.matcher.ElementMatchers; -import net.bytebuddy.utility.JavaModule; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * 增强普通类的Transformer,advice风格 - * - * @author HapThorin - * @version 1.0.0 - * @since 2022-01-24 - */ -public class AdviceTransformer implements AgentBuilder.Transformer { - /** - * 超类校验集 - */ - private static final Map>> SUPERTYPE_VERIFY_MAP = new HashMap<>(); - - /** - * 拦截器全局集 - */ - private static final Map>> INTERCEPTOR_GLOBAL_MAP = new HashMap<>(); - - /** - * 拦截声明器数组 - */ - private final InterceptDeclarer[] interceptDeclarers; - - /** - * 超类生命器数组 - */ - private final SuperTypeDeclarer[] superTypeDeclarers; - - public AdviceTransformer(InterceptDeclarer[] interceptDeclarers, SuperTypeDeclarer[] superTypeDeclarers) { - this.interceptDeclarers = interceptDeclarers; - this.superTypeDeclarers = superTypeDeclarers; - } - - @Override - public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDesc, - ClassLoader classLoader, JavaModule module) { - final int verifiedKey = Objects.hash(classLoader, typeDesc.getActualName()); - DynamicType.Builder newBuilder = builder; - newBuilder = extendsFromSuperTypes(newBuilder, typeDesc, verifiedKey); - newBuilder = enhanceMethods(newBuilder, typeDesc, classLoader, verifiedKey); - return newBuilder; - } - - /** - * 让被增强类实现超类接口集 - *

注意,指定超类本身为被增强类超类时,不实现;若通过超类尝试多次被实现时,仅第一次生效 - * - * @param builder 构建器 - * @param typeDesc 类定义 - * @param verifiedKey 校验键 - * @return 构建器 - */ - private DynamicType.Builder extendsFromSuperTypes(DynamicType.Builder builder, TypeDescription typeDesc, - int verifiedKey) { - if (superTypeDeclarers == null || superTypeDeclarers.length <= 0) { - return builder; - } - Set> superTypeSet = SUPERTYPE_VERIFY_MAP.get(verifiedKey); - if (superTypeSet == null) { - superTypeSet = new HashSet<>(); - SUPERTYPE_VERIFY_MAP.put(verifiedKey, superTypeSet); - } - DynamicType.Builder newBuilder = builder; - for (SuperTypeDeclarer superTypeDeclarer : superTypeDeclarers) { - final Class superType = superTypeDeclarer.getSuperType(); - if (typeDesc.isAssignableTo(superType) || superTypeSet.contains(superType)) { - continue; - } - newBuilder = superTypeDeclarer.resolve(superType, newBuilder); - superTypeSet.add(superType); - } - return newBuilder; - } - - /** - * 检查类定义的所有方法,并尝试增强: - *

-     *     1.初次增强时,添加必要参数,见{@link #defineEssentialFields}
-     *     2.遍历所有定义的方法,并尝试增强,见{@link #enhanceMethod}
-     * 
- * 注意,native方法,抽象方法,及父类定义的方法不会被检查 - * - * @param builder 构建器 - * @param typeDesc 类定义 - * @param classLoader 被增强类的类加载器 - * @param verifiedKey 校验键 - * @return 构建器 - */ - private DynamicType.Builder enhanceMethods(DynamicType.Builder builder, TypeDescription typeDesc, - ClassLoader classLoader, int verifiedKey) { - if (interceptDeclarers == null || interceptDeclarers.length <= 0) { - return builder; - } - DynamicType.Builder newBuilder = builder; - Map> interceptorMap = INTERCEPTOR_GLOBAL_MAP.get(verifiedKey); - if (interceptorMap == null) { - interceptorMap = new HashMap<>(); - INTERCEPTOR_GLOBAL_MAP.put(verifiedKey, interceptorMap); - newBuilder = defineEssentialFields(newBuilder, interceptorMap); - } - for (MethodDescription.InDefinedShape methodDesc : typeDesc.getDeclaredMethods()) { - if (methodDesc.isNative() || methodDesc.isAbstract()) { - continue; - } - newBuilder = enhanceMethod(newBuilder, methodDesc, classLoader, interceptorMap); - } - return newBuilder; - } - - /** - * 为被增强类添加必要参数: - *
-     *     1.用于存放拦截器的集合
-     *     2.用于存放额外静态属性的集合
-     *     3.用于存放额外成员属性的集合
-     * 
- * - * @param builder 构建器 - * @param interceptorMap 拦截器集合 - * @return 构建器 - */ - private DynamicType.Builder defineEssentialFields(DynamicType.Builder builder, - Map> interceptorMap) { - return builder.defineField("_INTERCEPTOR_MAP_$SERMANT", Map.class, Visibility.PRIVATE, Ownership.STATIC) - .initializer(new LoadedTypeInitializer.ForStaticField("_INTERCEPTOR_MAP_$SERMANT", interceptorMap)) - .defineField("_EXT_STATIC_FIELDS_$SERMANT", Map.class, Visibility.PRIVATE, Ownership.STATIC) - .defineField("_EXT_MEMBER_FIELDS_$SERMANT", Map.class, Visibility.PRIVATE, Ownership.MEMBER); - } - - /** - * 对单个方法进行增强 - * - * @param builder 构建器 - * @param methodDesc 方法定义 - * @param classLoader 加载被增强类的类加载器 - * @param interceptorMap 拦截器集合 - * @return 构建器 - */ - private DynamicType.Builder enhanceMethod(DynamicType.Builder builder, - MethodDescription.InDefinedShape methodDesc, ClassLoader classLoader, - Map> interceptorMap) { - final List declaredInterceptors = getInterceptors(methodDesc, classLoader); - if (declaredInterceptors.isEmpty()) { - return builder; - } - final String methodKey = MethodKeyCreator.getMethodDescKey(methodDesc); - final List interceptors = interceptorMap.get(methodKey); - DynamicType.Builder newBuilder = builder; - if (interceptors == null) { - if (methodDesc.isStatic()) { - newBuilder = newBuilder.visit(Advice.to(AdviceStaticTemplate.class).on(ElementMatchers.is(methodDesc))); - } else if (methodDesc.isConstructor()) { - newBuilder = newBuilder.visit(Advice.to(AdviceConstTemplate.class).on(ElementMatchers.is(methodDesc))); - } else { - newBuilder = newBuilder.visit(Advice.to(AdviceMemberTemplate.class).on(ElementMatchers.is(methodDesc))); - } - interceptorMap.put(methodKey, declaredInterceptors); - } else { - interceptors.addAll(declaredInterceptors); - } - return newBuilder; - } - - /** - * 从拦截声明器中获取所有符合条件的拦截器 - * - * @param methodDesc 方法定义 - * @param classLoader 被增强类的类加载器 - * @return 拦截器集合 - */ - private List getInterceptors(MethodDescription.InDefinedShape methodDesc, ClassLoader classLoader) { - final List interceptors = new ArrayList<>(); - for (InterceptDeclarer declarer : interceptDeclarers) { - if (!declarer.getMethodMatcher().matches(methodDesc)) { - continue; - } - interceptors.addAll(Arrays.asList(declarer.getInterceptors(classLoader))); - } - return interceptors; - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/BootstrapTransformer.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/BootstrapTransformer.java deleted file mode 100644 index 3ef9dd2fa5..0000000000 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/BootstrapTransformer.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (C) 2021-2021 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.transformer; - -import com.huaweicloud.sermant.core.common.LoggerFactory; -import com.huaweicloud.sermant.core.plugin.agent.declarer.InterceptDeclarer; -import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; -import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; -import com.huaweicloud.sermant.core.plugin.agent.template.BootstrapConstTemplate; -import com.huaweicloud.sermant.core.plugin.agent.template.BootstrapMemberTemplate; -import com.huaweicloud.sermant.core.plugin.agent.template.BootstrapStaticTemplate; -import com.huaweicloud.sermant.core.plugin.agent.template.CommonMethodAdviser; -import com.huaweicloud.sermant.core.plugin.agent.template.MethodKeyCreator; -import com.huaweicloud.sermant.core.utils.ClassLoaderUtils; - -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.method.MethodList; -import net.bytebuddy.description.modifier.Ownership; -import net.bytebuddy.description.modifier.Visibility; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.dynamic.ClassFileLocator; -import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.matcher.ElementMatchers; -import net.bytebuddy.utility.JavaModule; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Locale; -import java.util.Map; -import java.util.logging.Logger; - -/** - * 启动类加载器加载类的Transformer,advice风格 - * - * @author HapThorin - * @version 1.0.0 - * @since 2021-10-27 - */ -public class BootstrapTransformer implements AgentBuilder.Transformer { - /** - * bootstrap模板的拦截器列表字段名称 - */ - public static final String INTERCEPTORS_FIELD_NAME = "_INTERCEPTORS_$SERMANT"; - - /** - * bootstrap模板的拦截器列表字段名称 - */ - public static final String METHODS_MAP_NAME = "_METHODS_MAP_$SERMANT"; - - /** - * 用来缓存用于系统类增强的反射方法的Map - */ - private static final HashMap METHODS_HASH_MAP = new HashMap<>(); - - static { - try { - METHODS_HASH_MAP.put("forMemberMethod", ExecuteContext.class.getDeclaredMethod("forMemberMethod", - Object.class, Method.class, Object[].class, Map.class, Map.class)); - METHODS_HASH_MAP.put("forConstructor", ExecuteContext.class.getDeclaredMethod("forConstructor", Class.class, - Constructor.class, Object[].class, Map.class)); - METHODS_HASH_MAP.put("forStaticMethod", ExecuteContext.class.getDeclaredMethod("forStaticMethod", - Class.class, Method.class, Object[].class, Map.class)); - METHODS_HASH_MAP.put("onMethodEnter", - CommonMethodAdviser.class.getDeclaredMethod("onMethodEnter", ExecuteContext.class, ListIterator.class)); - METHODS_HASH_MAP.put("onMethodExit", - CommonMethodAdviser.class.getDeclaredMethod("onMethodExit", ExecuteContext.class, ListIterator.class)); - METHODS_HASH_MAP.put("isSkip", ExecuteContext.class.getDeclaredMethod("isSkip")); - METHODS_HASH_MAP.put("getArguments", ExecuteContext.class.getDeclaredMethod("getArguments")); - METHODS_HASH_MAP.put("afterMethod", - ExecuteContext.class.getDeclaredMethod("afterMethod", Object.class, Throwable.class)); - METHODS_HASH_MAP.put("getResult", ExecuteContext.class.getDeclaredMethod("getResult")); - METHODS_HASH_MAP.put("afterConstructor", - ExecuteContext.class.getDeclaredMethod("afterConstructor", Object.class, Map.class)); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - /** - * 日志 - */ - private static final Logger LOGGER = LoggerFactory.getLogger(); - - /** - * 拦截器全局集 - */ - private static final Map> INTERCEPTOR_GLOBAL_MAP = new HashMap<>(); - - /** - * 拦截定义数组 - */ - private final InterceptDeclarer[] interceptDeclarers; - - /** - * 构造方法 - * - * @param interceptDeclarers interceptDeclarers - */ - public BootstrapTransformer(InterceptDeclarer[] interceptDeclarers) { - this.interceptDeclarers = interceptDeclarers; - } - - @Override - public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDesc, - ClassLoader classLoader, JavaModule module) { - if (interceptDeclarers == null || interceptDeclarers.length <= 0) { - return builder; - } - return enhanceMethods(builder, typeDesc, ClassLoader.getSystemClassLoader()); - } - - /** - * 检查类定义的所有方法,并尝试增强,见{@link #enhanceMethod} - *

注意,native方法,抽象方法,及父类定义的方法不会被检查 - * - * @param builder 构建器 - * @param typeDesc 类定义 - * @param classLoader 加载被增强类的类加载器 - * @return 构建器 - */ - private DynamicType.Builder enhanceMethods(DynamicType.Builder builder, TypeDescription typeDesc, - ClassLoader classLoader) { - final MethodList declaredMethods = typeDesc.getDeclaredMethods(); - DynamicType.Builder newBuilder = builder; - for (MethodDescription.InDefinedShape methodDesc : declaredMethods) { - if (methodDesc.isNative() || methodDesc.isAbstract()) { - continue; - } - newBuilder = enhanceMethod(newBuilder, methodDesc, classLoader); - } - return newBuilder; - } - - /** - * 对单个方法进行增强 - * - * @param builder 构建器 - * @param methodDesc 方法定义 - * @param classLoader 加载被增强类的类加载器 - * @return 构建器 - */ - private DynamicType.Builder enhanceMethod(DynamicType.Builder builder, - MethodDescription.InDefinedShape methodDesc, ClassLoader classLoader) { - final List interceptors = getInterceptors(methodDesc, classLoader); - if (interceptors.isEmpty()) { - return builder; - } - try { - if (methodDesc.isStatic()) { - return resolve(builder, methodDesc, interceptors, BootstrapStaticTemplate.class, classLoader); - } else if (methodDesc.isConstructor()) { - return resolve(builder, methodDesc, interceptors, BootstrapConstTemplate.class, classLoader); - } else { - return resolve(builder, methodDesc, interceptors, BootstrapMemberTemplate.class, classLoader); - } - } catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - LOGGER.warning(String.format(Locale.ROOT, "Enhance [%s] failed for [%s], caused by [%s]. ", - MethodKeyCreator.getMethodDescKey(methodDesc), e.getClass().getName(), e.getMessage())); - } - return builder; - } - - /** - * 获取单个方法有关的拦截器列表 - * - * @param methodDesc 方法定义 - * @param classLoader 类加载器 - * @return 拦截器列表 - */ - private List getInterceptors(MethodDescription.InDefinedShape methodDesc, ClassLoader classLoader) { - final List interceptors = new ArrayList<>(); - for (InterceptDeclarer declarer : interceptDeclarers) { - if (!declarer.getMethodMatcher().matches(methodDesc)) { - continue; - } - interceptors.addAll(Arrays.asList(declarer.getInterceptors(classLoader))); - } - return interceptors; - } - - /** - * 处理方法增强 - *

-     *     1.依模板类创建增强Adviser
-     *     2.使用被增强类的类加载器定义该Adviser
-     *     3.为该Adviser添加增强的拦截器
-     *     4.在构建器中定义增强逻辑
-     * 
- * - * @param builder 构建器 - * @param methodDesc 方法定义 - * @param interceptors 拦截器列表 - * @param templateCls 增强模板类 - * @param classLoader 被增强类的类加载器 - * @return 构建器 - * @throws InvocationTargetException 调用方法错误 - * @throws IllegalAccessException 无法访问属性或方法,正常不会报出 - * @throws NoSuchMethodException 无法找到方法,正常不会报出 - * @throws NoSuchFieldException 找不到属性 - */ - private DynamicType.Builder resolve(DynamicType.Builder builder, MethodDescription.InDefinedShape methodDesc, - List interceptors, Class templateCls, ClassLoader classLoader) - throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException { - final String adviceClassName = getAdviceClassName(templateCls, methodDesc); - List globalInterceptors = INTERCEPTOR_GLOBAL_MAP.get(adviceClassName); - if (globalInterceptors == null) { - globalInterceptors = new ArrayList<>(interceptors); - INTERCEPTOR_GLOBAL_MAP.put(adviceClassName, globalInterceptors); - final byte[] adviceClsBytes = createAdviceClass(templateCls, adviceClassName); - final Class adviceCls = defineAdviceClass(adviceClassName, classLoader, adviceClsBytes); - prepareAdviceClass(adviceCls, interceptors); - return visitAdvice(builder, methodDesc, adviceCls, adviceClsBytes); - } else { - globalInterceptors.addAll(interceptors); - return builder; - } - } - - /** - * 获取增强Adviser的全限定名 - *

由模板类全限定名拼接被增强方法元信息的hash值所得,见于{@link MethodKeyCreator#getMethodDescKey} - * - * @param templateCls 增强模板类 - * @param methodDesc 方法定义 - * @return 增强Adviser全限定名 - */ - private String getAdviceClassName(Class templateCls, MethodDescription.InDefinedShape methodDesc) { - return templateCls.getName() + "_" - + Integer.toHexString(MethodKeyCreator.getMethodDescKey(methodDesc).hashCode()); - } - - /** - * 使用byte-buddy依照增强模板类动态生成增强Adviser - * - * @param templateCls 增强模板类 - * @param adviceClsName 增强Adviser全限定名 - * @return 增强Adviser的字节码 - */ - private byte[] createAdviceClass(Class templateCls, String adviceClsName) { - return new ByteBuddy().redefine(templateCls) - .name(adviceClsName) - .defineField(INTERCEPTORS_FIELD_NAME, List.class, Visibility.PUBLIC, Ownership.STATIC) - .defineField(METHODS_MAP_NAME,Map.class,Visibility.PUBLIC, Ownership.STATIC) - .make() - .getBytes(); - } - - /** - * 通过字节码,使用ClassLoader定义增强Adviser - * - * @param adviceClassName 增强Advice的全限定名 - * @param classLoader 被增强类的ClassLoader - * @param adviceClsBytes 增强Adviser的字节码 - * @return 增强Adviser的Class - * @throws InvocationTargetException 调用defineClass方法错误 - * @throws IllegalAccessException 无法访问defineClass方法,正常不会报出 - * @throws NoSuchMethodException 无法找到defineClass方法,正常不会报出 - */ - private Class defineAdviceClass(String adviceClassName, ClassLoader classLoader, byte[] adviceClsBytes) - throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { - return ClassLoaderUtils.defineClass(adviceClassName, classLoader, adviceClsBytes); - } - - /** - * 初始化增强Adviser,为其添加方法拦截器集合 - * - * @param adviceCls 增强Adviser的Class - * @param interceptors 拦截器集合 - * @throws NoSuchFieldException 找不到属性 - * @throws IllegalAccessException 无法访问属性 - */ - private void prepareAdviceClass(Class adviceCls, List interceptors) - throws NoSuchFieldException, IllegalAccessException { - adviceCls.getDeclaredField(INTERCEPTORS_FIELD_NAME).set(null, interceptors); - adviceCls.getDeclaredField(METHODS_MAP_NAME).set(null, METHODS_HASH_MAP); - } - - /** - * 在构建器中定义增强逻辑 - * - * @param builder 构建器 - * @param methodDesc 方法定义 - * @param adviceCls 增强Adviser的Class - * @param adviceClsBytes 增强Adviser的字节码 - * @return 构建器 - */ - private DynamicType.Builder visitAdvice(DynamicType.Builder builder, - MethodDescription.InDefinedShape methodDesc, Class adviceCls, final byte[] adviceClsBytes) { - return builder.visit(Advice.to(adviceCls, new ClassFileLocator() { - @Override - public void close() { - } - - @Override - public Resolution locate(String name) { - return new Resolution.Explicit(adviceClsBytes); - } - }).on(ElementMatchers.is(methodDesc))); - } -} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/DefaultTransformer.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/DefaultTransformer.java new file mode 100644 index 0000000000..d603dc931d --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/transformer/DefaultTransformer.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.transformer; + +import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.core.plugin.agent.declarer.InterceptDeclarer; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; +import com.huaweicloud.sermant.core.plugin.agent.template.BaseAdviseHandler; +import com.huaweicloud.sermant.core.plugin.agent.template.MethodKeyCreator; +import com.huaweicloud.sermant.core.plugin.agent.template.TemplateForCtor; +import com.huaweicloud.sermant.core.plugin.agent.template.TemplateForMember; +import com.huaweicloud.sermant.core.plugin.agent.template.TemplateForStatic; + +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.MethodList; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.matcher.ElementMatchers; +import net.bytebuddy.utility.JavaModule; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.logging.Logger; + +/** + * 类的Transformer,advice风格 + * + * @author luanwenfei + * @since 2023-07-18 + */ +public class DefaultTransformer implements AgentBuilder.Transformer { + /** + * 日志 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(); + + /** + * 拦截定义数组 + */ + private final InterceptDeclarer[] interceptDeclarers; + + /** + * 构造方法 + * + * @param interceptDeclarers interceptDeclarers + */ + public DefaultTransformer(InterceptDeclarer[] interceptDeclarers) { + this.interceptDeclarers = interceptDeclarers; + } + + @Override + public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDesc, + ClassLoader classLoader, JavaModule module) { + if (interceptDeclarers == null || interceptDeclarers.length == 0) { + return builder; + } + return enhanceMethods(builder, typeDesc, classLoader); + } + + /** + * 检查类定义的所有方法,并尝试增强,见{@link #enhanceMethod} + *

注意,native方法,抽象方法,及父类定义的方法不会被检查 + * + * @param builder 构建器 + * @param typeDesc 类定义 + * @param classLoader 加载被增强类的类加载器 + * @return 构建器 + */ + private DynamicType.Builder enhanceMethods(DynamicType.Builder builder, TypeDescription typeDesc, + ClassLoader classLoader) { + final MethodList declaredMethods = typeDesc.getDeclaredMethods(); + DynamicType.Builder newBuilder = builder; + for (MethodDescription.InDefinedShape methodDesc : declaredMethods) { + if (methodDesc.isNative() || methodDesc.isAbstract()) { + continue; + } + newBuilder = enhanceMethod(newBuilder, methodDesc, classLoader); + } + return newBuilder; + } + + /** + * 对单个方法进行增强 + * + * @param builder 构建器 + * @param methodDesc 方法定义 + * @param classLoader 加载被增强类的类加载器 + * @return 构建器 + */ + private DynamicType.Builder enhanceMethod(DynamicType.Builder builder, + MethodDescription.InDefinedShape methodDesc, ClassLoader classLoader) { + final List interceptors = getInterceptors(methodDesc, classLoader); + if (interceptors.isEmpty()) { + return builder; + } + try { + if (methodDesc.isStatic()) { + return resolve(builder, methodDesc, interceptors, TemplateForStatic.class, classLoader); + } else if (methodDesc.isConstructor()) { + return resolve(builder, methodDesc, interceptors, TemplateForCtor.class, classLoader); + } else { + return resolve(builder, methodDesc, interceptors, TemplateForMember.class, classLoader); + } + } catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + LOGGER.warning(String.format(Locale.ROOT, "Enhance [%s] failed for [%s], caused by [%s]. ", + MethodKeyCreator.getMethodDescKey(methodDesc), e.getClass().getName(), e.getMessage())); + } + return builder; + } + + /** + * 获取单个方法有关的拦截器列表 + * + * @param methodDesc 方法定义 + * @param classLoader 类加载器 + * @return 拦截器列表 + */ + private List getInterceptors(MethodDescription.InDefinedShape methodDesc, ClassLoader classLoader) { + final List interceptors = new ArrayList<>(); + for (InterceptDeclarer declarer : interceptDeclarers) { + if (!declarer.getMethodMatcher().matches(methodDesc)) { + continue; + } + if (classLoader == null) { + interceptors.addAll(Arrays.asList(declarer.getInterceptors(ClassLoader.getSystemClassLoader()))); + } else { + interceptors.addAll(Arrays.asList(declarer.getInterceptors(classLoader))); + } + } + return interceptors; + } + + /** + * 处理方法增强 + *

+     *     1.依模板类创建增强Adviser
+     *     2.使用被增强类的类加载器定义该Adviser
+     *     3.为该Adviser添加增强的拦截器
+     *     4.在构建器中定义增强逻辑
+     * 
+ * + * @param builder 构建器 + * @param methodDesc 方法定义 + * @param interceptors 拦截器列表 + * @param templateCls 增强模板类 + * @return 构建器 + * @throws InvocationTargetException 调用方法错误 + * @throws IllegalAccessException 无法访问属性或方法,正常不会报出 + * @throws NoSuchMethodException 无法找到方法,正常不会报出 + * @throws NoSuchFieldException 找不到属性 + */ + private DynamicType.Builder resolve(DynamicType.Builder builder, MethodDescription.InDefinedShape methodDesc, + List interceptors, Class templateCls, ClassLoader classLoader) + throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException { + final String adviceKey = getAdviceKey(templateCls, classLoader, methodDesc); + List interceptorsForMethod = BaseAdviseHandler.getInterceptorListMap().get(adviceKey); + if (interceptorsForMethod == null) { + interceptorsForMethod = new ArrayList<>(interceptors); + BaseAdviseHandler.getInterceptorListMap().put(adviceKey, interceptorsForMethod); + return builder.visit(Advice.to(templateCls).on(ElementMatchers.is(methodDesc))); + } else { + interceptorsForMethod.addAll(interceptors); + return builder; + } + } + + /** + * 组成AdviceKey的格式为[模板类标准类名_被增强方法元信息的hash值_被增强类的类加载器],被增强方法元信息,见于{@link MethodKeyCreator#getMethodDescKey} + * + * @param templateCls 增强模板类 + * @return 增强Adviser全限定名 + */ + private String getAdviceKey(Class templateCls, + ClassLoader classLoader, MethodDescription.InDefinedShape methodDesc) { + return templateCls.getSimpleName() + "_" + + Integer.toHexString(MethodKeyCreator.getMethodDescKey(methodDesc).hashCode()) + "_" + classLoader; + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/utils/ClassUtils.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/utils/ClassUtils.java index cfb0873839..8d61a451eb 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/utils/ClassUtils.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/utils/ClassUtils.java @@ -23,6 +23,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.Locale; import java.util.Optional; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -91,7 +92,7 @@ public static Optional> loadClass(String className, ClassLoader classLo } catch (ClassNotFoundException | NoClassDefFoundError ignored) { final String message = String.format(Locale.ENGLISH, "Can not load class [%s]!", className); if (isNeedWarn) { - LOGGER.warning(message); + LOGGER.log(Level.WARNING, message, ignored); } else { LOGGER.fine(message); } diff --git a/sermant-agentcore/sermant-agentcore-god/pom.xml b/sermant-agentcore/sermant-agentcore-god/pom.xml new file mode 100644 index 0000000000..2203fe48cb --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-god/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + com.huaweicloud.sermant + sermant-agentcore + 1.0.0 + + + sermant-agentcore-god + + + 8 + 8 + + ${pom.basedir}/../.. + ${sermant.basedir}/${sermant.name}-${project.version} + + + + + agent + + true + + + + + org.apache.maven.plugins + maven-shade-plugin + + + ${package.temp.dir}/agent/god/${project.artifactId}-${project.version}.jar + + + + + + + + test + + + + org.apache.maven.plugins + maven-shade-plugin + + + ${package.temp.dir}/agent/god/${project.artifactId}-${project.version}.jar + + + + + + + + release + + + + org.apache.maven.plugins + maven-shade-plugin + + + + + + + \ No newline at end of file diff --git a/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserInterface.java b/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserInterface.java new file mode 100644 index 0000000000..267a0a9b38 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserInterface.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.adviser; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; + +/** + * 转换器接口 + * + * @author luanwenfei + * @since 2023-04-11 + */ +public interface AdviserInterface { + /** + * 调用方法的前置触发点 + * + * @param context 执行上下文 + * @param adviceKey 被增强类名 + * @return 执行上下文 + * @throws Throwable Throwable + */ + ExecuteContext onMethodEnter(ExecuteContext context, String adviceKey) throws Throwable; + + /** + * 调用方法的后置触发点 + * + * @param context 执行上下文 + * @param adviceKey 被增强类名 + * @return 执行上下文 + * @throws Throwable Throwable + */ + ExecuteContext onMethodExit(ExecuteContext context, String adviceKey) throws Throwable; +} diff --git a/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserScheduler.java b/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserScheduler.java new file mode 100644 index 0000000000..e989297ad2 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/adviser/AdviserScheduler.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.core.plugin.agent.adviser; + +import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext; + +/** + * 转换器调度器 + * + * @author luanwenfei + * @since 2023-04-11 + */ +public class AdviserScheduler { + private static AdviserInterface currentAdviser; + + private AdviserScheduler() { + } + + /** + * 注册一个 Adviser + * + * @param adviser adviser + */ + public static void registry(AdviserInterface adviser) { + currentAdviser = adviser; + } + + /** + * 取消注册一个 Adviser + * + * @param adviser adviser + */ + public static void unRegistry(AdviserInterface adviser) { + currentAdviser = null; + } + + /** + * 调度方法入口的Adviser逻辑 + * + * @param context 执行上下文 + * @param adviceKey advice的关键字,由类和方法描述、advice模板、被增强类的类加载器组成 + * @return 执行上下文 + * @throws Throwable Throwable + */ + public static ExecuteContext onMethodEnter(Object context, String adviceKey) throws Throwable { + ExecuteContext executeContext = (ExecuteContext) context; + if (currentAdviser != null) { + executeContext = currentAdviser.onMethodEnter(executeContext, adviceKey); + } + return executeContext; + } + + /** + * 调度方法出口的Adviser逻辑 + * + * @param context 执行上下文 + * @param adviceKey advice的关键字,由类和方法描述、advice模板、被增强类的类加载器组成 + * @return 执行上下文 + * @throws Throwable Throwable + */ + public static ExecuteContext onMethodExit(Object context, String adviceKey) throws Throwable { + ExecuteContext executeContext = (ExecuteContext) context; + if (currentAdviser != null) { + executeContext = currentAdviser.onMethodExit(executeContext, adviceKey); + } + return executeContext; + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/entity/ExecuteContext.java b/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/entity/ExecuteContext.java similarity index 90% rename from sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/entity/ExecuteContext.java rename to sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/entity/ExecuteContext.java index eb0f00811c..fef1f421d3 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/entity/ExecuteContext.java +++ b/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/entity/ExecuteContext.java @@ -16,12 +16,15 @@ package com.huaweicloud.sermant.core.plugin.agent.entity; +import com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor; + import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.HashMap; +import java.util.ListIterator; import java.util.Map; /** @@ -36,14 +39,17 @@ public class ExecuteContext { * 被增强的类 */ private final Class rawCls; + /** * 被增强的构造函数,注意:增强方法时为空 */ private final Constructor constructor; + /** * 被增强的方法,注意:增强构造函数时为空 */ private final Method method; + /** * 被增强的对象,注意: *
@@ -52,6 +58,7 @@ public class ExecuteContext {
      * 
*/ private Object object; + /** * 被增强的方法入参 */ @@ -78,12 +85,12 @@ public class ExecuteContext { private Throwable throwableOut; /** - * 额外的静态属性 + * 额外的静态属性,贯穿执行上下文过程 */ private Map extStaticFields; /** - * 额外的成员属性 + * 额外的成员属性,贯穿执行上下文过程 */ private Map extMemberFields; @@ -92,73 +99,72 @@ public class ExecuteContext { */ private Map localFields; + /** + * 拦截器双向迭代器 + */ + private ListIterator interceptorIterator; + /** * 原生字段集,每次获取的字段都会暂时保存在此 */ private Map rawFields; private ExecuteContext(Object object, Class rawCls, Constructor constructor, Method method, - Object[] arguments, Map extStaticFields, Map extMemberFields) { + Object[] arguments) { this.object = object; this.rawCls = rawCls; this.constructor = constructor; this.method = method; this.arguments = arguments; - this.isSkip = false; - this.result = null; - this.throwable = null; - this.extStaticFields = extStaticFields; - this.extMemberFields = extMemberFields; - this.localFields = null; } /** * 创建构造函数的执行上下文 * - * @param cls 被增强的类 - * @param constructor 被增强的构造函数 - * @param arguments 构造函数入参 + * @param cls 被增强的类 + * @param constructor 被增强的构造函数 + * @param arguments 构造函数入参 * @param extStaticFields 额外的静态属性集 * @return 执行上下文 */ public static ExecuteContext forConstructor(Class cls, Constructor constructor, Object[] arguments, Map extStaticFields) { - return new ExecuteContext(null, cls, constructor, null, arguments, extStaticFields, null); + return new ExecuteContext(null, cls, constructor, null, arguments); } /** * 创建成员方法的执行上下文 * - * @param object 被增强的对象 - * @param method 被增强的方法 - * @param arguments 方法的入参 + * @param object 被增强的对象 + * @param method 被增强的方法 + * @param arguments 方法的入参 * @param extStaticFields 额外的静态属性集 * @param extMemberFields 额外的成员属性集 * @return 执行上下文 */ public static ExecuteContext forMemberMethod(Object object, Method method, Object[] arguments, Map extStaticFields, Map extMemberFields) { - return new ExecuteContext(object, object.getClass(), null, method, arguments, extStaticFields, extMemberFields); + return new ExecuteContext(object, object.getClass(), null, method, arguments); } /** * 构建静态方法的执行上下文 * - * @param cls 被增强的类 - * @param method 被增强的方法 - * @param arguments 方法的入参 + * @param cls 被增强的类 + * @param method 被增强的方法 + * @param arguments 方法的入参 * @param extStaticFields 额外的静态属性集 * @return 执行上下文 */ public static ExecuteContext forStaticMethod(Class cls, Method method, Object[] arguments, Map extStaticFields) { - return new ExecuteContext(null, cls, null, method, arguments, extStaticFields, null); + return new ExecuteContext(null, cls, null, method, arguments); } /** * 适配增强构造函数时的后置触发点 * - * @param thisObj 构造的对象 + * @param thisObj 构造的对象 * @param thisExtMemberFields 成员属性集 * @return 执行上下文 */ @@ -171,7 +177,7 @@ public ExecuteContext afterConstructor(Object thisObj, Map thisE /** * 适配增强静态方法和成员方法时的后置触发点 * - * @param methodResult 方法主要流程结果 + * @param methodResult 方法主要流程结果 * @param methodThrowable 方法主要流程异常 * @return 执行上下文 */ @@ -225,6 +231,15 @@ public Map getExtMemberFields() { return extMemberFields; } + public ListIterator getInterceptorIterator() { + return interceptorIterator; + } + + public void setInterceptorIterator( + ListIterator interceptorIterator) { + this.interceptorIterator = interceptorIterator; + } + /** * 检索属性,静态和成员属性都在此检索,仅检索被增强类定义的属性及其公有的属性,超类protected的属性将不会被获取 * @@ -303,8 +318,8 @@ private Field getMemberField(String fieldName) throws NoSuchFieldException { * 设置原生静态属性值 * * @param fieldName 属性名 - * @param value 属性值 - * @throws NoSuchFieldException 找不到该属性 + * @param value 属性值 + * @throws NoSuchFieldException 找不到该属性 * @throws IllegalAccessException 属性访问失败 */ public void setRawStaticFieldValue(String fieldName, Object value) @@ -316,8 +331,9 @@ public void setRawStaticFieldValue(String fieldName, Object value) * 设置额外静态属性值 * * @param fieldName 属性名 - * @param value 属性值 + * @param value 属性值 */ + @Deprecated public void setExtStaticFieldValue(String fieldName, Object value) { if (extStaticFields == null) { extStaticFields = new HashMap<>(); @@ -325,11 +341,47 @@ public void setExtStaticFieldValue(String fieldName, Object value) { extStaticFields.put(fieldName, value); } + /** + * 获取额外静态属性值 + * + * @param fieldName 属性名 + * @return 属性值 + */ + @Deprecated + public Object getExtStaticFieldValue(String fieldName) { + return extStaticFields == null ? null : extStaticFields.get(fieldName); + } + + /** + * 设置额外成员属性值 + * + * @param fieldName 属性名 + * @param value 属性值 + */ + @Deprecated + public void setExtMemberFieldValue(String fieldName, Object value) { + if (extMemberFields == null) { + extMemberFields = new HashMap<>(); + } + extMemberFields.put(fieldName, value); + } + + /** + * 获取额外成员属性值 + * + * @param fieldName 属性名 + * @return 属性值 + */ + @Deprecated + public Object getExtMemberFieldValue(String fieldName) { + return extMemberFields == null ? null : extMemberFields.get(fieldName); + } + /** * 设置静态属性值,原生静态属性不存在时,写入额外静态属性集中 * * @param fieldName 属性名 - * @param value 属性值 + * @param value 属性值 */ public void setStaticFieldValue(String fieldName, Object value) { try { @@ -344,7 +396,7 @@ public void setStaticFieldValue(String fieldName, Object value) { * * @param fieldName 属性名 * @return 属性值 - * @throws NoSuchFieldException 找不到该属性 + * @throws NoSuchFieldException 找不到该属性 * @throws IllegalAccessException 属性访问失败 */ public Object getRawStaticFieldValue(String fieldName) @@ -352,16 +404,6 @@ public Object getRawStaticFieldValue(String fieldName) return getStaticField(fieldName).get(null); } - /** - * 获取额外静态属性值 - * - * @param fieldName 属性名 - * @return 属性值 - */ - public Object getExtStaticFieldValue(String fieldName) { - return extStaticFields == null ? null : extStaticFields.get(fieldName); - } - /** * 获取静态属性值,原生静态属性不存在时,从额外静态属性中获取 * @@ -380,8 +422,8 @@ public Object getStaticFieldValue(String fieldName) { * 设置原生成员属性值 * * @param fieldName 属性名 - * @param value 属性值 - * @throws NoSuchFieldException 找不到该属性 + * @param value 属性值 + * @throws NoSuchFieldException 找不到该属性 * @throws IllegalAccessException 属性访问失败 */ public void setRawMemberFieldValue(String fieldName, Object value) @@ -389,19 +431,6 @@ public void setRawMemberFieldValue(String fieldName, Object value) getMemberField(fieldName).set(object, value); } - /** - * 设置额外成员属性值 - * - * @param fieldName 属性名 - * @param value 属性值 - */ - public void setExtMemberFieldValue(String fieldName, Object value) { - if (extMemberFields == null) { - extMemberFields = new HashMap<>(); - } - extMemberFields.put(fieldName, value); - } - /** * 设置成员属性值,原生成员属性不存在时,写入额外成员属性集中 * @@ -426,7 +455,7 @@ public void setMemberFieldValue(String fieldName, Object value) { * * @param fieldName 属性名 * @return 属性值 - * @throws NoSuchFieldException 找不到该属性 + * @throws NoSuchFieldException 找不到该属性 * @throws IllegalAccessException 属性访问失败 */ public Object getRawMemberFieldValue(String fieldName) @@ -434,16 +463,6 @@ public Object getRawMemberFieldValue(String fieldName) return getMemberField(fieldName).get(object); } - /** - * 获取额外成员属性值 - * - * @param fieldName 属性名 - * @return 属性值 - */ - public Object getExtMemberFieldValue(String fieldName) { - return extMemberFields == null ? null : extMemberFields.get(fieldName); - } - /** * 获取成员属性值,原生成员属性不存在时,从额外成员属性中获取 * @@ -467,7 +486,7 @@ public Object getMemberFieldValue(String fieldName) { * 设置局部属性值 * * @param fieldName 属性名 - * @param value 属性值 + * @param value 属性值 */ public void setLocalFieldValue(String fieldName, Object value) { if (localFields == null) { diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/interceptor/Interceptor.java b/sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/interceptor/Interceptor.java similarity index 100% rename from sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/interceptor/Interceptor.java rename to sermant-agentcore/sermant-agentcore-god/src/main/java/com/huaweicloud/sermant/core/plugin/agent/interceptor/Interceptor.java diff --git a/sermant-agentcore/sermant-agentcore-premain/pom.xml b/sermant-agentcore/sermant-agentcore-premain/pom.xml index e772d9a1c4..e61c8af2ad 100644 --- a/sermant-agentcore/sermant-agentcore-premain/pom.xml +++ b/sermant-agentcore/sermant-agentcore-premain/pom.xml @@ -112,7 +112,7 @@ - com.huawei.sermant.premain.AgentPremain + com.huawei.sermant.premain.AgentLauncher true true diff --git a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/AgentPremain.java b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/AgentLauncher.java similarity index 59% rename from sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/AgentPremain.java rename to sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/AgentLauncher.java index 724b8cf016..b4c910fcfa 100644 --- a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/AgentPremain.java +++ b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/AgentLauncher.java @@ -30,6 +30,7 @@ import java.net.BindException; import java.security.acl.NotOwnerException; import java.sql.SQLException; +import java.time.LocalDateTime; import java.util.ConcurrentModificationException; import java.util.Locale; import java.util.Map; @@ -42,18 +43,19 @@ import java.util.logging.Logger; import javax.naming.InsufficientResourcesException; + /** - * Agent Premain方法 + * Agent 启动器,包含premain方式启动和AgentMain方式启动 * * @author luanwenfei * @since 2022-03-26 */ -public class AgentPremain { - private static boolean executeFlag = false; - +public class AgentLauncher { private static final Logger LOGGER = getLogger(); - private AgentPremain() { + private static boolean installFlag = false; + + private AgentLauncher() { } /** @@ -61,26 +63,43 @@ private AgentPremain() { * * @param agentArgs agentArgs * @param instrumentation instrumentation - * @throws DupPremainException */ public static void premain(String agentArgs, Instrumentation instrumentation) { + launchAgent(agentArgs, instrumentation, false); + } + + /** + * agentmain + * + * @param agentArgs agentArgs + * @param instrumentation instrumentation + */ + public static void agentmain(String agentArgs, Instrumentation instrumentation) { + launchAgent(agentArgs, instrumentation, true); + } + + private static void launchAgent(String agentArgs, Instrumentation instrumentation, Boolean dynamicInstall) { try { - // 执行标记,防止重复运行 - if (executeFlag) { + if (installFlag) { throw new DupPremainException(); } - executeFlag = true; + + installFlag = true; + + // 添加引导库 + LOGGER.info("Loading god library into BootstrapClassLoader..."); + loadGodLib(instrumentation); // 添加核心库 - LOGGER.info("Loading core library... "); + LOGGER.info("Loading core library..."); loadCoreLib(instrumentation); // 初始化启动参数 - LOGGER.info("Building argument map... "); + LOGGER.info("Building argument map..."); final Map argsMap = BootArgsBuilder.build(agentArgs); // agent core入口 - LOGGER.info("Loading sermant agent... "); + LOGGER.info("Loading sermant agent..."); AgentCoreEntrance.run(argsMap, instrumentation); LOGGER.info("Load sermant done. "); @@ -90,7 +109,7 @@ public static void premain(String agentArgs, Instrumentation instrumentation) { LOGGER.severe("Loading sermant agent failed. "); } catch (Exception e) { LOGGER.severe( - String.format(Locale.ROOT, "Loading sermant agent failed, %s. ", e)); + String.format(Locale.ROOT, "Loading sermant agent failed, %s. ", e)); } } @@ -99,40 +118,52 @@ private static void loadCoreLib(Instrumentation instrumentation) throws IOExcept if (!coreDir.exists() || !coreDir.isDirectory()) { throw new RuntimeException("core directory is not exist or is not directory."); } - final File[] jars = coreDir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".jar"); - } - }); - if (jars == null || jars.length <= 0) { + final File[] jars = coreDir.listFiles((dir, name) -> name.endsWith(".jar")); + if (jars == null || jars.length == 0) { throw new RuntimeException("core directory is empty"); } for (File jar : jars) { - JarFile jarFile = null; - try { - jarFile = new JarFile(jar); + try (JarFile jarFile = new JarFile(jar)) { instrumentation.appendToSystemClassLoaderSearch(jarFile); - } finally { - if (jarFile != null) { - try { - jarFile.close(); - } catch (IOException ignored) { - LOGGER.severe(ignored.getMessage()); - } - } + } catch (IOException ioException) { + LOGGER.severe(ioException.getMessage()); + } + } + } + + private static void loadGodLib(Instrumentation instrumentation) throws IOException { + final File bootstrapDir = new File(PathDeclarer.getGodLibPath()); + if (!bootstrapDir.exists() || !bootstrapDir.isDirectory()) { + throw new RuntimeException("God directory is not exist or is not directory."); + } + File[] jars = bootstrapDir.listFiles((dir, name) -> name.endsWith(".jar")); + if (jars == null || jars.length == 0) { + throw new RuntimeException("God directory is empty"); + } + + for (File jar : jars) { + try (JarFile jarFile = new JarFile(jar)) { + instrumentation.appendToBootstrapClassLoaderSearch(jarFile); + } catch (IOException ioException) { + LOGGER.severe(ioException.getMessage()); } } } - private static Logger getLogger() { + /** + * 获取sermant.agent日志 + * + * @return Logger + */ + public static Logger getLogger() { final Logger logger = Logger.getLogger("sermant.agent"); final ConsoleHandler handler = new ConsoleHandler(); final String lineSeparator = System.getProperty("line.separator"); handler.setFormatter(new Formatter() { @Override public String format(LogRecord record) { - return "[" + record.getLevel() + "] " + record.getMessage() + lineSeparator; + String time = LocalDateTime.now().toString(); + return "[" + time + "] " + "[" + record.getLevel() + "] " + record.getMessage() + lineSeparator; } }); logger.addHandler(handler); diff --git a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/common/PathDeclarer.java b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/common/PathDeclarer.java index f4e679a263..4195360c47 100644 --- a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/common/PathDeclarer.java +++ b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huawei/sermant/premain/common/PathDeclarer.java @@ -49,6 +49,15 @@ public static String getCorePath() { return getAgentPath() + File.separatorChar + "core"; } + /** + * 获取引导包目录 + * + * @return 引导包目录 + */ + public static String getGodLibPath() { + return getAgentPath() + File.separatorChar + "god"; + } + /** * 获取核心功能实现包目录 *