Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

合并为增强引导类加载器加载的类而定制的Template、Transform #1272

Merged
merged 1 commit into from
Aug 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions sermant-agentcore/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>sermant-agentcore-god</module>
<module>sermant-agentcore-core</module>
<module>sermant-agentcore-premain</module>
<module>sermant-agentcore-config</module>
Expand All @@ -55,6 +56,7 @@
<profile>
<id>test</id>
<modules>
<module>sermant-agentcore-god</module>
<module>sermant-agentcore-core</module>
<module>sermant-agentcore-premain</module>
<module>sermant-agentcore-config</module>
Expand All @@ -64,6 +66,7 @@
<profile>
<id>release</id>
<modules>
<module>sermant-agentcore-god</module>
<module>sermant-agentcore-core</module>
<module>sermant-agentcore-premain</module>
<module>sermant-agentcore-implement</module>
Expand Down
5 changes: 5 additions & 0 deletions sermant-agentcore/sermant-agentcore-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@
</profiles>

<dependencies>
<dependency>
<groupId>com.huaweicloud.sermant</groupId>
<artifactId>sermant-agentcore-god</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.huaweicloud.sermant.core.config.ConfigManager;
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;
Expand Down Expand Up @@ -66,5 +68,9 @@ public static void run(Map<String, Object> argsMap, Instrumentation instrumentat

// 初始化插件
PluginSystemEntrance.initialize(instrumentation);

// 注册Adviser
DefaultAdviser defaultAdviser = new DefaultAdviser();
AdviserScheduler.registry(defaultAdviser);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,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;
Expand All @@ -43,6 +43,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
Expand Down Expand Up @@ -193,13 +194,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(folder);
} 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());
}
}
}));
Expand Down Expand Up @@ -242,11 +242,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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
* 插件收集器管理器,用于从所有插件收集器中获取插件描述器
Expand All @@ -48,6 +43,8 @@
* @since 2022-01-26
*/
public class PluginCollectorManager {
private static final Logger LOGGER = LoggerFactory.getLogger();

/**
* 通过spi检索所有配置的插件收集器
*/
Expand All @@ -73,7 +70,7 @@
*/
public static List<PluginDescription> getPlugins(AgentConfig.CombineStrategy strategy) {
final List<PluginDescription> plugins = new ArrayList<>();
plugins.addAll(combinePlugins(getDeclarers(), strategy));
plugins.addAll(combinePlugins(getDeclarers()));
plugins.addAll(getDescriptions());
return plugins;
}
Expand Down Expand Up @@ -114,27 +111,12 @@
* 合并所有的插件声明器
*
* @param declarers 插件声明器列表
* @param strategy 插件声明器合并策略
* @return 合并所得的插件描述器列表
*/
private static List<PluginDescription> combinePlugins(List<? extends PluginDeclarer> declarers,
AgentConfig.CombineStrategy strategy) {
private static List<PluginDescription> combinePlugins(List<? extends PluginDeclarer> declarers) {
final List<PluginDescription> 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;
}
Expand Down Expand Up @@ -163,170 +145,25 @@
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<PluginDescription> combineDeclarersByName(Iterable<? extends PluginDeclarer> declarers) {
final List<PluginDescription> plugins = new ArrayList<>();
final Map<String, List<PluginDeclarer>> nameCombinedMap = new HashMap<>();
for (PluginDeclarer pluginDeclarer : declarers) {
final ClassMatcher classMatcher = pluginDeclarer.getClassMatcher();
if (classMatcher instanceof ClassTypeMatcher) {
for (String typeName : ((ClassTypeMatcher) classMatcher).getTypeNames()) {
List<PluginDeclarer> 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<String, List<PluginDeclarer>> 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<? extends PluginDeclarer> declarers) {
final Map<String, List<PluginDeclarer>> nameCombinedMap = new HashMap<>();
final List<PluginDeclarer> combinedList = new ArrayList<>();
for (PluginDeclarer pluginDeclarer : declarers) {
final ClassMatcher classMatcher = pluginDeclarer.getClassMatcher();
if (classMatcher instanceof ClassTypeMatcher) {
for (String typeName : ((ClassTypeMatcher) classMatcher).getTypeNames()) {
List<PluginDeclarer> 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<String, List<PluginDeclarer>> nameCombinedMap,
List<PluginDeclarer> 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<PluginDeclarer> 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<String, List<PluginDeclarer>> nameCombinedMap) {
final List<PluginDeclarer> pluginDeclarers = nameCombinedMap.remove(typeDescription.getActualName());
final List<InterceptDeclarer> 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<SuperTypeDeclarer> 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<TypeDescription> matcher, TypeDescription target) {
try {
return matcher.matches(target);
} catch (Exception exception) {

Check failure on line 163 in sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/collector/PluginCollectorManager.java

View workflow job for this annotation

GitHub Actions / Checkstyle

[Checkstyle Check] reported by reviewdog 🐶 Catching 'Exception' is not allowed. Raw Output: /home/runner/work/Sermant/Sermant/./sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/agent/collector/PluginCollectorManager.java:163:11: error: Catching 'Exception' is not allowed. (com.puppycrawl.tools.checkstyle.checks.coding.IllegalCatchCheck)
LOGGER.log(Level.WARNING, "Exception occurs when math target: " + target.getActualName() + ",{0}",
exception.getMessage());
return false;
}
}
}
Loading
Loading