SkyWalking源码-- Agent 启动流程

361 阅读2分钟

本文基于 SkyWalking-Java-agent 8.15.0 版本

Java agent

两种方式

静态启动

以命令参数的方式启动:
-javaagent: jarpath[ =options]

  • jarpath:agent JAR 文件的绝对路径
  • options:agent可选项

public static void premain(String agentArgs, Instrumentation inst);

如果agent没有实现该方法的话,JVM会采用尝试访问以下方法:

public static void premain(String agentArgs);

动态附加

JVM 启动后再启动 agent

public static void agentmain(String agentArgs, Instrumentation inst);

如果agent没有实现该方法的话,JVM会采用尝试访问以下方法:

public static void agentmain(String agentArgs);

参考:docs.oracle.com/javase/8/do…

SkyWalking agent

采用 静态启动 的方式,将 Java agent 嵌入到 Java 应用里面,通过代理 JVM 上运行的服务,修改字节码实现信息的获取。SkyWalking agent 的入口是 org.apache.skywalking.apm.agent.SkyWalkingAgent

启动流程

image.png

初始化配置

try {    
    // 1.初始化配置
    SnifferConfigInitializer.initializeCoreConfig(agentArgs);  
} catch (Exception e) {  
    // try to resolve a new logger, and use the new logger to write the error log here  
    LogManager.getLogger(SkyWalkingAgent.class)  
              .error(e, "SkyWalking agent initialized failure. Shutting down.");  
    return;  
} finally {  
    // refresh logger again after initialization finishes  
    LOGGER = LogManager.getLogger(SkyWalkingAgent.class);  
}

agentArgs:agent的参数。启动agent时,会通过 -javaagent的方式,比如:

  • -javaagent:/path/to/agent.jar=agentArgs
  • -javaagent:/path/to/agent.jar=k1=v1,k2=v2...
    第一个 = 后面的均为 agentArgs 的参数。agentArgs 使用 = 将键值拼凑到 jarpath 的后面

-javaagent参数必须在-jar之前

SkyWalking源码-- Agent 初始化配置

加载插件

try {  
    // 2.加载插件  
    pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());  
} 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;  
}

定制化 Agent 行为

// 3.定制化Agent行为  
// 创建 ByteBuddy 实例  
final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));  
// 指定 ByteBuddy 要忽略的类  
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()));  
    
    // 1)将必要的类注入到Bootstrap ClassLoader  
    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;  
}  
// 解决JDK模块系统的跨模块类访问  
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;  
}  
// 将修改后的字节码保存到磁盘/内存上  
if (Config.Agent.IS_CACHE_ENHANCED_CLASS) {  
    try {  
        agentBuilder = agentBuilder.with(new CacheableTransformerDecorator(Config.Agent.CLASS_CACHE_MODE));  
        LOGGER.info("SkyWalking agent class cache [{}] activated.", Config.Agent.CLASS_CACHE_MODE);  
    } catch (Exception e) {  
        LOGGER.error(e, "SkyWalking agent can't active class cache.");  
    }  
}  
  
agentBuilder.type(pluginFinder.buildMatch())   
    .transform(new Transformer(pluginFinder))  
    .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) 
    .with(new RedefinitionListener())  
    .with(new Listener())  
    .installOn(instrumentation);  
  

加载服务

try {  
    // 4.启动服务
    ServiceManager.INSTANCE.boot();  
} catch (Exception e) {  
    LOGGER.error(e, "Skywalking agent boot failure.");  
}

注册关闭钩子

// 5.注册关闭钩子
Runtime.getRuntime()  
    .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));