SkyWalking Java Agent 配置初始化流程分析

本文介绍了SkyWalkingJavaAgent如何从不同来源(系统属性、环境变量和配置文件)加载配置,包括overrideConfigBySystemProp()、overrideConfigByAgentOptions()和initializeConfig()方法,以及配置项的映射和验证过程。还详细解释了配置文件路径查找和配置优先级规则。
摘要由CSDN通过智能技术生成

public String resolvePlaceholder(String placeholderName) {

return getConfigValue(placeholderName, properties);

}

});

}

// 优先级 System.Properties(-D) > System environment variables > Config file

private String getConfigValue(String key, final Properties properties) {

// 从Java虚拟机系统属性中获取(-D)

String value = System.getProperty(key);

if (value == null) {

// 从操作系统环境变量获取, 比如 JAVA_HOME、Path 等环境变量

value = System.getenv(key);

}

if (value == null) {

// 从配置文件中获取

value = properties.getProperty(key);

}

return value;

}

复制代码

3.overrideConfigBySystemProp() 读取 System.getProperties() 中以 skywalking. 开头的系统属性覆盖配置;

/**

  • Override the config by system properties. The property key must start with skywalking, the result should be as

  • same as in agent.config

  • such as: Property key of agent.service_name should be skywalking.agent.service_name

*/

private static void overrideConfigBySystemProp() throws IllegalAccessException {

Properties systemProperties = System.getProperties();

for (final Map.Entry<Object, Object> prop : systemProperties.entrySet()) {

String key = prop.getKey().toString();

// 必须是以 skywalking. 开头的属性

if (key.startsWith(ENV_KEY_PREFIX)) {

String realKey = key.substring(ENV_KEY_PREFIX.length());

AGENT_SETTINGS.put(realKey, prop.getValue());

}

}

}

复制代码

4.overrideConfigByAgentOptions() 解析 agentArgs 参数配置覆盖配置;

  • agentArgs 就是 premain 方法的第一个参数,以 -javaagent:/path/to/skywalking-agent.jar=k1=v1,k2=v2的形式传值。

5.initializeConfig() 将以上读取到的配置信息映射到 Config 类的静态属性,后面会重点分析;

6.configureLogger() 根据配置的 Config.Logging.RESOLVER 重配置 Log,更多关于日志参见文章 SkyWalking Java Agent 日志组件分析

static void configureLogger() {

switch (Config.Logging.RESOLVER) {

case JSON:

LogManager.setLogResolver(new JsonLogResolver());

break;

case PATTERN:

default:

LogManager.setLogResolver(new PatternLogResolver());

}

}

复制代码

7.必填参数验证,验证非空参数 agent.service_name 和 collector.servers。

定位 skywalking-agent.jar 所在目录

skywalking-agent 目录结构如下:

skywalking-agent.png

config 目录存放的是默认配置文件 agent.config,读取默认配置文件,以及后面加载插件都需要用到 skywalking-agent.jar 所在目录。

/**

  • Load the specified config file or default config file

  • @return the config file {@link InputStream}, or null if not needEnhance.

*/

private static InputStreamReader loadConfig() throws AgentPackageNotFoundException, ConfigNotFoundException {

// System.getProperty() 读取 Java 虚拟机中的系统属性, Java 虚拟机中的系统属性在运行Java程序的时候通过 java -Dk1=v1 配置.

String specifiedConfigPath = System.getProperty(SPECIFIED_CONFIG_PATH);

// 使用指定的配置文件或默认的配置文件, AgentPackagePath.getPath() 获取 skywalking-agent.jar 所在目录

File configFile = StringUtil.isEmpty(specifiedConfigPath) ? new File(

AgentPackagePath.getPath(), DEFAULT_CONFIG_FILE_NAME) : new File(specifiedConfigPath);

if (configFile.exists() && configFile.isFile()) {

try {

LOGGER.info(“Config file found in {}.”, configFile);

return new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8);

} catch (FileNotFoundException e) {

throw new ConfigNotFoundException(“Failed to load agent.config”, e);

}

}

throw new ConfigNotFoundException(“Failed to load agent.config.”);

}

复制代码

new File(AgentPackagePath.getPath(), DEFAULT_CONFIG_FILE_NAME) 定位默认配置文件的位置, AgentPackagePath.getPath() 方法用来获取 skywalking-agent.jar 所在目录

/**

  • AgentPackagePath is a flag and finder to locate the SkyWalking agent.jar. It gets the absolute path of the agent jar.

  • The path is the required metadata for agent core looking up the plugins and toolkit activations. If the lookup

  • mechanism fails, the agent will exit directly.

*/

public class AgentPackagePath {

private static final ILog LOGGER = LogManager.getLogger(AgentPackagePath.class);

private static File AGENT_PACKAGE_PATH;

public static File getPath() throws AgentPackageNotFoundException {

if (AGENT_PACKAGE_PATH == null) {

// 返回 skywalking-agent.jar 文件所在的目录 E:\develop\source\sample\source\skywalking-java\skywalking-agent

AGENT_PACKAGE_PATH = findPath();

}

return AGENT_PACKAGE_PATH;

}

public static boolean isPathFound() {

return AGENT_PACKAGE_PATH != null;

}

private static File findPath() throws AgentPackageNotFoundException {

// 将 AgentPackagePath 全类名中的.替换成 /

// org/apache/skywalking/apm/agent/core/boot/AgentPackagePath.class

String classResourcePath = AgentPackagePath.class.getName().replaceAll(“.”, “/”) + “.class”;

// 使用 AppClassLoader 加载资源,通常情况下 AgentPackagePath 类是被 AppClassLoader 加载的。

URL resource = ClassLoader.getSystemClassLoader().getResource(classResourcePath);

if (resource != null) {

String urlString = resource.toString();

//jar:file:/E:/source/skywalking-java/skywalking-agent/skywalking-agent.jar!/org/apache/skywalking/apm/agent/core/boot/AgentPackagePath.class

LOGGER.debug(“The beacon class location is {}.”, urlString);

// 判断 url 中是否包含!,如果包含则说明 AgentPackagePath.class 是包含在jar中。

int insidePathIndex = urlString.indexOf(‘!’);

boolean isInJar = insidePathIndex > -1;

if (isInJar) {

// file:/E:/source/skywalking-java/skywalking-agent/skywalking-agent.jar

urlString = urlString.substring(urlString.indexOf(“file:”), insidePathIndex);

File agentJarFile = null;

try {

// E:\source\skywalking-java\skywalking-agent\skywalking-agent.jar

agentJarFile = new File(new URL(urlString).toURI());

} catch (MalformedURLException | URISyntaxException e) {

LOGGER.error(e, “Can not locate agent jar file by url:” + urlString);

}

if (agentJarFile.exists()) {

// 返回 skywalking-agent.jar 文件所在的目录

return agentJarFile.getParentFile();

}

} else {

int prefixLength = “file:”.length();

String classLocation = urlString.substring(

prefixLength, urlString.length() - classResourcePath.length());

return new File(classLocation);

}

}

LOGGER.error(“Can not locate agent jar file.”);

throw new AgentPackageNotFoundException(“Can not locate agent jar file.”);

}

}

复制代码

通过类加载器 AppClassLoader 加载 AgentPackagePath.class 资源,定位到 skywalking-agent.jar 所在的目录,保存到静态成员变量 AGENT_PACKAGE_PATH 中,下次获取直接读取静态变量。

配置优先级

Agent Options > System.Properties(-D) > System environment variables > Config file

System.getProperties() 和 System.getenv() 区别,请参考文章 www.cnblogs.com/clarke157/p…

  • System.getProperties() 获取 Java 虚拟机相关的系统属性(比如 java.version、 java.io.tmpdir 等),通过 java -D配置;

  • System.getenv() 获取系统环境变量(比如 JAVA_HOME、Path 等),通过操作系统配置。

将配置信息映射到 Config 类

在我们的日常开发中一般是直接从 Properties 读取需要的配置项,SkyWalking Java Agent 并没有这么做,而是定义一个配置类 Config,将配置项映射到 Config 类的静态属性中,其他地方需要配置项的时候,直接从类的静态属性获取就可以了,非常方便使用。

ConfigInitializer 就是负责将 Properties 中的 key/value 键值对映射到类(比如 Config 类)的静态属性,其中 key 对应类的静态属性,value 赋值给静态属性的值。

/**

  • This is the core config in sniffer agent.

*/

public class Config {

public static class Agent {

/**

  • Namespace isolates headers in cross process propagation. The HEADER name will be HeaderName:Namespace.

*/

public static String NAMESPACE = “”;

/**

  • Service name is showed in skywalking-ui. Suggestion: set a unique name for each service, service instance

  • nodes share the same code

*/

@Length(50)

public static String SERVICE_NAME = “”;

// 省略部分代码…

}

public static class Collector {

/**

  • Collector skywalking trace receiver service addresses.

*/

public static String BACKEND_SERVICE = “”;

// 省略部分代码…

}

// 省略部分代码…

public static class Logging {

/**

  • Log file name.

*/

public static String FILE_NAME = “skywalking-api.log”;

/**

  • Log files directory. Default is blank string, means, use "{theSkywalkingAgentJarDir}/logs " to output logs.

  • {theSkywalkingAgentJarDir} is the directory where the skywalking agent jar file is located.

  • Ref to {@link WriterFactory#getLogWriter()}

*/

public static String DIR = “”;

}

// 省略部分代码…

}

复制代码

比如通过 agent.config 配置文件配置服务名称

The service name in UI

agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}

复制代码

  • agent 对应 Config 类的静态内部类 Agent ;

  • service_name 对应静态内部类 Agent 的静态属性 SERVICE_NAME。

SkyWalking Java Agent 在这里面使用了下划线而不是驼峰来命名配置项,将类的静态属性名称转换成下划线配置名称非常方便,直接转成小写就可以通过 Properties 获取对应的值了。

ConfigInitializer 类源码:

/**

  • Init a class’s static fields by a {@link Properties}, including static fields and static inner classes.

*/

public class ConfigInitializer {

public static void initialize(Properties properties, Class<?> rootConfigType) throws IllegalAccessException {

initNextLevel(properties, rootConfigType, new ConfigDesc());

}

private static void initNextLevel(Properties properties, Class<?> recentConfigType,

ConfigDesc parentDesc) throws IllegalArgumentException, IllegalAccessException {

for (Field field : recentConfigType.getFields()) {

if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {

String configKey = (parentDesc + “.” + field.getName()).toLowerCase();

Class<?> type = field.getType();

if (type.equals(Map.class)) {

/*

  • Map config format is, config_key[map_key]=map_value

  • Such as plugin.opgroup.resttemplate.rule[abc]=/url/path

*/

// Deduct two generic types of the map

ParameterizedType genericType = (ParameterizedType) field.getGenericType();

Type[] argumentTypes = genericType.getActualTypeArguments();

Type keyType = null;

Type valueType = null;

if (argumentTypes != null && argumentTypes.length == 2) {

// Get key type and value type of the map

keyType = argumentTypes[0];

valueType = argumentTypes[1];

}

Map map = (Map) field.get(null);

// Set the map from config key and properties

setForMapType(configKey, map, properties, keyType, valueType);

} else {

/*

  • Others typical field type

*/

String value = properties.getProperty(configKey);

// Convert the value into real type

final Length lengthDefine = field.getAnnotation(Length.class);

if (lengthDefine != null) {

if (value != null && value.length() > lengthDefine.value()) {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
ue()) {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-5WyoD5Po-1714955340453)]

[外链图片转存中…(img-KJWkZeR9-1714955340454)]

[外链图片转存中…(img-ne9saKPs-1714955340454)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值