SkyWalking(二)SkyWalkingAgent 初始化

2020年5月2日 | 作者 Siran | 1400字 | 阅读大约需要3分钟
归档于 Skywalking | 标签 #Skywalking

概述

SkyWalking 分为两个部分,一部分是探针用于收集指标,另一部分是服务端用于接收探针发来的指标进行展示。

其中SkyWalking 的探针是基于 JavaAgent 机制。可以通过以下两篇文章熟悉 JavaAgent

并且通过 ByteBuddy 修改 Java 类的二进制,通过以下文章熟悉 ByteBuddy

源码分析

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 {
        final PluginFinder pluginFinder;
        try {
            //① 初始化配置信息 该步骤中会加载 agent.config 配置文件,其中会检测 Java Agent 参数以及环境变量是否覆盖了相应配置项。
            SnifferConfigInitializer.initialize(agentArgs);
            //② 查找并解析skywalking-plugin.def 插件文件;
            // AgentClassLoader 加载插件类并进行实例化;PluginFinder 提供插件匹配的功能
            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;
        }
        //③ 使用Byte Buddy 库创建 AgentBuilder
        final ByteBuddy byteBuddy = new ByteBuddy()
            .with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));

        //④ 开始创建 AgentBuilder , AgentBuilder 是 Byte Buddy 库专门用来支持 Java Agent 的一个 API
        new AgentBuilder.Default(byteBuddy)  // 设置使用的ByteBuddy对象
            .ignore( //忽略指定包中的类,对这些类不会进行拦截增强。
                nameStartsWith("net.bytebuddy.")  // 不会拦截下列包中的类
                    .or(nameStartsWith("org.slf4j."))
                    .or(nameStartsWith("org.apache.logging."))
                    .or(nameStartsWith("org.groovy."))
                    .or(nameContains("javassist"))
                    .or(nameContains(".asm."))
                    .or(nameStartsWith("sun.reflect"))
                    .or(allSkyWalkingAgentExcludeToolkit()) // 处理 Skywalking 的类
                        // synthetic类和方法是由编译器生成的,这种类也需要忽略
                    .or(ElementMatchers.<TypeDescription>isSynthetic()))
            .type(pluginFinder.buildMatch())// 拦截  在类加载时根据传入的 ElementMatcher 进行拦截,拦截到的目标类将会被 transform() 方法中指定的 Transformer 进行增强。
            .transform(new Transformer(pluginFinder)) // 设置Transform 这里指定的 Transformer 会对前面拦截到的类进行增强。
                .with(new Listener())  // 设置Listener  添加一个 Listener 用来监听 AgentBuilder 触发的事件。
            .installOn(instrumentation);

        try {
            //⑤ 使用jdk spi 加载的方式并启动 BootService 服务
            ServiceManager.INSTANCE.boot();
        } catch (Exception e) {
            logger.error(e, "Skywalking agent boot failure.");
        }
        //⑥ 添加一个JVM 勾子
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override public void run() {
                ServiceManager.INSTANCE.shutdown();
            }
        }, "skywalking service shutdown thread"));
    }

    //内部类
    private static class Transformer implements AgentBuilder.Transformer {
        private PluginFinder pluginFinder;

        Transformer(PluginFinder pluginFinder) {
            this.pluginFinder = pluginFinder;
        }

        //插件增强目标类的入口
        //Skywalking.Transformer 会通过 PluginFinder 查找目标类匹配的插件(即 AbstractClassEnhancePluginDefine 对象),
        //然后交由 AbstractClassEnhancePluginDefine 完成增强
        @Override
        public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                                TypeDescription typeDescription,// 被拦截的目标类
                                                ClassLoader classLoader,  //加载目标类的ClassLoader
                                                JavaModule module) {
            // 从PluginFinder中查找匹配该目标类的插件
            List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);
            if (pluginDefines.size() > 0) {
                DynamicType.Builder<?> newBuilder = builder;
                EnhanceContext context = new EnhanceContext();
                for (AbstractClassEnhancePluginDefine define : pluginDefines) {
                    // AbstractClassEnhancePluginDefine.define()方法是插件入口,
                    // 在其中完成了对目标类的增强
                    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;
        }
    }

    private static ElementMatcher.Junction<NamedElement> allSkyWalkingAgentExcludeToolkit() {
        return nameStartsWith("org.apache.skywalking.").and(not(nameStartsWith("org.apache.skywalking.apm.toolkit.")));
    }

    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(typeDescription, 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) {
        }
    }
}
  • ① 初始化配置信息 该步骤中会加载 agent.config 配置文件,其中会检测 Java Agent 参数以及环境变量是否覆盖了相应配置项。
  • ② 查找并解析skywalking-plugin.def 插件文件;AgentClassLoader 加载插件类并进行实例化;PluginFinder 提供插件匹配的功能
  • ③ 使用Byte Buddy 库创建 AgentBuilder
  • ④ 开始创建 AgentBuilder , AgentBuilder 是 Byte Buddy 库专门用来支持 Java Agent 的一个 API
  • ⑤ 使用jdk spi 加载的方式并启动 BootService 服务
  • ⑥ 添加一个JVM 勾子

接下来的文章会一一分析每一步的实现。