序
本文主要研究一下SkyWalkingAgent
SkyWalkingAgent
skywalking-6.6.0/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java
public class SkyWalkingAgent {
private static final ILog logger = LogManager.getLogger(SkyWalkingAgent.class);
/**
* Main entrance. Use byte-buddy transform to enhance all classes, which define in plugins.
*
* @param agentArgs
* @param instrumentation
* @throws PluginException
*/
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException, IOException {
final PluginFinder pluginFinder;
try {
SnifferConfigInitializer.initialize(agentArgs);
pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
} catch (ConfigNotFoundException ce) {
logger.error(ce, "SkyWalking agent could not find config. Shutting down.");
return;
} catch (AgentPackageNotFoundException ape) {
logger.error(ape, "Locate agent.jar failure. Shutting down.");
return;
} catch (Exception e) {
logger.error(e, "SkyWalking agent initialized failure. Shutting down.");
return;
}
final ByteBuddy byteBuddy = new ByteBuddy()
.with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy)
.ignore(
nameStartsWith("net.bytebuddy.")
.or(nameStartsWith("org.slf4j."))
.or(nameStartsWith("org.groovy."))
.or(nameContains("javassist"))
.or(nameContains(".asm."))
.or(nameContains(".reflectasm."))
.or(nameStartsWith("sun.reflect"))
.or(allSkyWalkingAgentExcludeToolkit())
.or(ElementMatchers.isSynthetic()));
JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
try {
agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
} catch (Exception e) {
logger.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
return;
}
try {
agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses);
} catch (Exception e) {
logger.error(e, "SkyWalking agent open read edge in JDK 9+ failure. Shutting down.");
return;
}
agentBuilder
.type(pluginFinder.buildMatch())
.transform(new Transformer(pluginFinder))
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(new Listener())
.installOn(instrumentation);
try {
ServiceManager.INSTANCE.boot();
} catch (Exception e) {
logger.error(e, "Skywalking agent boot failure.");
}
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override public void run() {
ServiceManager.INSTANCE.shutdown();
}
}, "skywalking service shutdown thread"));
}
//......
}
- SkyWalkingAgent的premain方法首先通过SnifferConfigInitializer.initialize(agentArgs)进行初始化,然后执行new PluginFinder(new PluginBootstrap().loadPlugins()),之后创建AgentBuilder,设置ignore、type、transform、listener然后install;最后执行ServiceManager.INSTANCE.boot()并注册shutdownHook执行ServiceManager.INSTANCE.shutdown()
SnifferConfigInitializer
skywalking-6.6.0/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializer.java
public class SnifferConfigInitializer {
private static final ILog logger = LogManager.getLogger(SnifferConfigInitializer.class);
private static String SPECIFIED_CONFIG_PATH = "skywalking_config";
private static String DEFAULT_CONFIG_FILE_NAME = "/config/agent.config";
private static String ENV_KEY_PREFIX = "skywalking.";
private static boolean IS_INIT_COMPLETED = false;
/**
* If the specified agent config path is set, the agent will try to locate the specified agent config. If the
* specified agent config path is not set , the agent will try to locate `agent.config`, which should be in the
* /config directory of agent package.
*
* Also try to override the config by system.properties. All the keys in this place should
* start with {@link #ENV_KEY_PREFIX}. e.g. in env `skywalking.agent.service_name=yourAppName` to override
* `agent.service_name` in config file.
*
* At the end, `agent.service_name` and `collector.servers` must not be blank.
*/
public static void initialize(String agentOptions) throws ConfigNotFoundException, AgentPackageNotFoundException {
InputStreamReader configFileStream;
try {
configFileStream = loadConfig();
Properties properties = new Properties();
properties.load(configFileStream);
for (String key : properties.stringPropertyNames()) {
String value = (String)properties.get(key);
//replace the key's value. properties.replace(key,value) in jdk8+
properties.put(key, PropertyPlaceholderHelper.INSTANCE.replacePlaceholders(value, properties));
}
ConfigInitializer.initialize(properties, Config.class);
} catch (Exception e) {
logger.error(e, "Failed to read the config file, skywalking is going to run in default config.");
}
try {
overrideConfigBySystemProp();
} catch (Exception e) {
logger.error(e, "Failed to read the system properties.");
}
if (!StringUtil.isEmpty(agentOptions)) {
try {
agentOptions = agentOptions.trim();
logger.info("Agent options is {}.", agentOptions);
overrideConfigByAgentOptions(agentOptions);
} catch (Exception e) {
logger.error(e, "Failed to parse the agent options, val is {}.", agentOptions);
}
}
if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) {
throw new ExceptionInInitializerError("`agent.service_name` is missing.");
}
if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) {
throw new ExceptionInInitializerError("`collector.backend_service` is missing.");
}
if (Config.Plugin.PEER_MAX_LENGTH <= 3) {
logger.warn("PEER_MAX_LENGTH configuration:{} error, the default value of 200 will be used.", Config.Plugin.PEER_MAX_LENGTH);
Config.Plugin.PEER_MAX_LENGTH = 200;
}
IS_INIT_COMPLETED = true;
}
//......
}
- SnifferConfigInitializer主要用于加载skywalking的配置文件,默认是读取/config/agent.config文件
PluginBootstrap
skywalking-6.6.0/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/PluginBootstrap.java
public class PluginBootstrap {
private static final ILog logger = LogManager.getLogger(PluginBootstrap.class);
/**
* load all plugins.
*
* @return plugin definition list.
*/
public List loadPlugins() throws AgentPackageNotFoundException {
AgentClassLoader.initDefaultLoader();
PluginResourcesResolver resolver = new PluginResourcesResolver();
List resources = resolver.getResources();
if (resources == null || resources.size() == 0) {
logger.info("no plugin files (skywalking-plugin.def) found, continue to start application.");
return new ArrayList();
}
for (URL pluginUrl : resources) {
try {
PluginCfg.INSTANCE.load(pluginUrl.openStream());
} catch (Throwable t) {
logger.error(t, "plugin file [{}] init failure.", pluginUrl);
}
}
List pluginClassList = PluginCfg.INSTANCE.getPluginClassList();
List plugins = new ArrayList();
for (PluginDefine pluginDefine : pluginClassList) {
try {
logger.debug("loading plugin class {}.", pluginDefine.getDefineClass());
AbstractClassEnhancePluginDefine plugin =
(AbstractClassEnhancePluginDefine)Class.forName(pluginDefine.getDefineClass(),
true,
AgentClassLoader.getDefault())
.newInstance();
plugins.add(plugin);
} catch (Throwable t) {
logger.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass());
}
}
plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
return plugins;
}
}
- PluginBootstrap提供了loadPlugins方法,它通过PluginResourcesResolver来加载skywalking-plugin.def定义的plugin
PluginFinder
skywalking-6.6.0/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/PluginFinder.java
public class PluginFinder {
private final Map> nameMatchDefine = new HashMap>();
private final List signatureMatchDefine = new ArrayList();
private final List bootstrapClassMatchDefine = new ArrayList();
public PluginFinder(List plugins) {
for (AbstractClassEnhancePluginDefine plugin : plugins) {
ClassMatch match = plugin.enhanceClass();
if (match == null) {
continue;
}
if (match instanceof NameMatch) {
NameMatch nameMatch = (NameMatch)match;
LinkedList pluginDefines = nameMatchDefine.get(nameMatch.getClassName());
if (pluginDefines == null) {
pluginDefines = new LinkedList();
nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);
}
pluginDefines.add(plugin);
} else {
signatureMatchDefine.add(plugin);
}
if (plugin.isBootstrapInstrumentation()) {
bootstrapClassMatchDefine.add(plugin);
}
}
}
public List find(TypeDescription typeDescription) {
List matchedPlugins = new LinkedList();
String typeName = typeDescription.getTypeName();
if (nameMatchDefine.containsKey(typeName)) {
matchedPlugins.addAll(nameMatchDefine.get(typeName));
}
for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
IndirectMatch match = (IndirectMatch)pluginDefine.enhanceClass();
if (match.isMatch(typeDescription)) {
matchedPlugins.add(pluginDefine);
}
}
return matchedPlugins;
}
public ElementMatcher super TypeDescription> buildMatch() {
ElementMatcher.Junction judge = new AbstractJunction() {
@Override
public boolean matches(NamedElement target) {
return nameMatchDefine.containsKey(target.getActualName());
}
};
judge = judge.and(not(isInterface()));
for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) {
ClassMatch match = define.enhanceClass();
if (match instanceof IndirectMatch) {
judge = judge.or(((IndirectMatch)match).buildJunction());
}
}
return new ProtectiveShieldMatcher(judge);
}
public List getBootstrapClassMatchDefine() {
return bootstrapClassMatchDefine;
}
}
- PluginFinder的构造器接收AbstractClassEnhancePluginDefine列表,并提供了find方法用于根据typeDescription查找匹配的AbstractClassEnhancePluginDefine,以及buildMatch方法用于构造ProtectiveShieldMatcher
Transformer
skywalking-6.6.0/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java
private static class Transformer implements AgentBuilder.Transformer {
private PluginFinder pluginFinder;
Transformer(PluginFinder pluginFinder) {
this.pluginFinder = pluginFinder;
}
@Override
public DynamicType.Builder> transform(DynamicType.Builder> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
List pluginDefines = pluginFinder.find(typeDescription);
if (pluginDefines.size() > 0) {
DynamicType.Builder> newBuilder = builder;
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
DynamicType.Builder> possibleNewBuilder = define.define(typeDescription, newBuilder, classLoader, context);
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
}
if (context.isEnhanced()) {
logger.debug("Finish the prepare stage for {}.", typeDescription.getName());
}
return newBuilder;
}
logger.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());
return builder;
}
}
- Transformer实现了AgentBuilder.Transformer接口,其构造器要求输入pluginFinder;其transform方法通过pluginFinder.find(typeDescription)获取指定的pluginDefines,若不为空则遍历pluginDefines进行define返回possibleNewBuilder
Listener
skywalking-6.6.0/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java
private static class Listener implements AgentBuilder.Listener {
@Override
public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
}
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
boolean loaded, DynamicType dynamicType) {
if (logger.isDebugEnable()) {
logger.debug("On Transformation class {}.", typeDescription.getName());
}
InstrumentDebuggingClass.INSTANCE.log(dynamicType);
}
@Override
public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
boolean loaded) {
}
@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded,
Throwable throwable) {
logger.error("Enhance class " + typeName + " error.", throwable);
}
@Override
public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
}
}
- Listener实现了AgentBuilder.Listener接口,其onTransformation方法会进行打印debug日志,以及执行InstrumentDebuggingClass.INSTANCE.log(dynamicType);其onError方法则会打印error日志
ServiceManager
skywalking-6.6.0/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/boot/ServiceManager.java
public enum ServiceManager {
INSTANCE;
private static final ILog logger = LogManager.getLogger(ServiceManager.class);
private Map bootedServices = Collections.emptyMap();
public void boot() {
bootedServices = loadAllServices();
prepare();
startup();
onComplete();
}
public void shutdown() {
for (BootService service : bootedServices.values()) {
try {
service.shutdown();
} catch (Throwable e) {
logger.error(e, "ServiceManager try to shutdown [{}] fail.", service.getClass().getName());
}
}
}
private Map loadAllServices() {
Map bootedServices = new LinkedHashMap();
List allServices = new LinkedList();
load(allServices);
Iterator serviceIterator = allServices.iterator();
while (serviceIterator.hasNext()) {
BootService bootService = serviceIterator.next();
Class extends BootService> bootServiceClass = bootService.getClass();
boolean isDefaultImplementor = bootServiceClass.isAnnotationPresent(DefaultImplementor.class);
if (isDefaultImplementor) {
if (!bootedServices.containsKey(bootServiceClass)) {
bootedServices.put(bootServiceClass, bootService);
} else {
//ignore the default service
}
} else {
OverrideImplementor overrideImplementor = bootServiceClass.getAnnotation(OverrideImplementor.class);
if (overrideImplementor == null) {
if (!bootedServices.containsKey(bootServiceClass)) {
bootedServices.put(bootServiceClass, bootService);
} else {
throw new ServiceConflictException("Duplicate service define for :" + bootServiceClass);
}
} else {
Class extends BootService> targetService = overrideImplementor.value();
if (bootedServices.containsKey(targetService)) {
boolean presentDefault = bootedServices.get(targetService).getClass().isAnnotationPresent(DefaultImplementor.class);
if (presentDefault) {
bootedServices.put(targetService, bootService);
} else {
throw new ServiceConflictException("Service " + bootServiceClass + " overrides conflict, " +
"exist more than one service want to override :" + targetService);
}
} else {
bootedServices.put(targetService, bootService);
}
}
}
}
return bootedServices;
}
private void prepare() {
for (BootService service : bootedServices.values()) {
try {
service.prepare();
} catch (Throwable e) {
logger.error(e, "ServiceManager try to pre-start [{}] fail.", service.getClass().getName());
}
}
}
private void startup() {
for (BootService service : bootedServices.values()) {
try {
service.boot();
} catch (Throwable e) {
logger.error(e, "ServiceManager try to start [{}] fail.", service.getClass().getName());
}
}
}
private void onComplete() {
for (BootService service : bootedServices.values()) {
try {
service.onComplete();
} catch (Throwable e) {
logger.error(e, "Service [{}] AfterBoot process fails.", service.getClass().getName());
}
}
}
/**
* Find a {@link BootService} implementation, which is already started.
*
* @param serviceClass class name.
* @param {@link BootService} implementation class.
* @return {@link BootService} instance
*/
public T findService(Class serviceClass) {
return (T)bootedServices.get(serviceClass);
}
void load(List allServices) {
Iterator iterator = ServiceLoader.load(BootService.class, AgentClassLoader.getDefault()).iterator();
while (iterator.hasNext()) {
allServices.add(iterator.next());
}
}
}
- ServiceManager是个枚举,它有个INSTANCE单例,其boot方法主要执行loadAllServices、prepare、startup、onComplete;其shutdown方法则遍历bootedServices挨个执行service.shutdown();loadAllServices方法通过ServiceLoader.load(BootService.class, AgentClassLoader.getDefault()).iterator()加载BootService;prepare、startup、onComplete都是遍历bootedServices分别执行service.prepare()、service.boot()、service.onComplete()
小结
SkyWalkingAgent的premain方法首先通过SnifferConfigInitializer.initialize(agentArgs)进行初始化,然后执行new PluginFinder(new PluginBootstrap().loadPlugins()),之后创建AgentBuilder,设置ignore、type、transform、listener然后install;最后执行ServiceManager.INSTANCE.boot()并注册shutdownHook执行ServiceManager.INSTANCE.shutdown()
doc
- SkyWalkingAgent