聊聊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.<TypeDescription>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.

* <p>

* 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.

* <p>

* 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<AbstractClassEnhancePluginDefine> loadPlugins() throws AgentPackageNotFoundException {

AgentClassLoader.initDefaultLoader();

PluginResourcesResolver resolver = new PluginResourcesResolver();

List<URL> 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<AbstractClassEnhancePluginDefine>();

}

for (URL pluginUrl : resources) {

try {

PluginCfg.INSTANCE.load(pluginUrl.openStream());

} catch (Throwable t) {

logger.error(t, "plugin file [{}] init failure.", pluginUrl);

}

}

List<PluginDefine> pluginClassList = PluginCfg.INSTANCE.getPluginClassList();

List<AbstractClassEnhancePluginDefine> plugins = new ArrayList<AbstractClassEnhancePluginDefine>();

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<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();

private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();

private final List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();

public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {

for (AbstractClassEnhancePluginDefine plugin : plugins) {

ClassMatch match = plugin.enhanceClass();

if (match == null) {

continue;

}

if (match instanceof NameMatch) {

NameMatch nameMatch = (NameMatch)match;

LinkedList<AbstractClassEnhancePluginDefine> pluginDefines = nameMatchDefine.get(nameMatch.getClassName());

if (pluginDefines == null) {

pluginDefines = new LinkedList<AbstractClassEnhancePluginDefine>();

nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);

}

pluginDefines.add(plugin);

} else {

signatureMatchDefine.add(plugin);

}

if (plugin.isBootstrapInstrumentation()) {

bootstrapClassMatchDefine.add(plugin);

}

}

}

public List<AbstractClassEnhancePluginDefine> find(TypeDescription typeDescription) {

List<AbstractClassEnhancePluginDefine> matchedPlugins = new LinkedList<AbstractClassEnhancePluginDefine>();

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<NamedElement>() {

@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<AbstractClassEnhancePluginDefine> 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<AbstractClassEnhancePluginDefine> 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<Class, BootService> 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<Class, BootService> loadAllServices() {

Map<Class, BootService> bootedServices = new LinkedHashMap<Class, BootService>();

List<BootService> allServices = new LinkedList<BootService>();

load(allServices);

Iterator<BootService> 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 <T> {@link BootService} implementation class.

* @return {@link BootService} instance

*/

public <T extends BootService> T findService(Class<T> serviceClass) {

return (T)bootedServices.get(serviceClass);

}

void load(List<BootService> allServices) {

Iterator<BootService> 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

以上是 聊聊SkyWalkingAgent 的全部内容, 来源链接: utcz.com/z/513749.html

回到顶部