skywalking源码--agent配置加载

本源码来自于skywalking-agent 8.9.0版本
本节主要讲解skywalking-agent的配置文件加载流程,该实现在 apm-sniffer模块的apm-agent-core 模块里面。但是入口依然是在 apm-agent 模块的 SkyWalkingAgent 的premain方法里面。

注:本篇文章主要是作为自己看书后的总结,内容有可能会存在一些个人理解上的偏差,如果有网友找出问题欢迎提出,感谢!!!如果我理解上的错误误导了您,在此表示抱歉!!!

相关源码

org.apache.skywalking.apm.agent.SkyWalkingAgent 类


try {
            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);
        }

这里 SnifferConfigInitializer.initializeCoreConfig(agentArgs) 就是加载配置的入口。

疑问

这里来个小问题,为什么加载配置的时候再catch的里面打印日志时需要通过 LogManager.getLogger 重新获取日志类型,而不是直接打印日志?这个等文章结尾再讲解

org.apache.skywalking.apm.agent.core.conf.SnifferConfigInitializer 类

public static void initializeCoreConfig(String agentOptions) {
        AGENT_SETTINGS = new Properties();
        try (final InputStreamReader configFileStream = loadConfig()) {
            AGENT_SETTINGS.load(configFileStream);
            for (String key : AGENT_SETTINGS.stringPropertyNames()) {
                String value = (String) AGENT_SETTINGS.get(key);
                AGENT_SETTINGS.put(key, PropertyPlaceholderHelper.INSTANCE.replacePlaceholders(value, AGENT_SETTINGS));
            }

        } 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.");
        }

        agentOptions = StringUtil.trim(agentOptions, ',');
        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);
            }
        }

        initializeConfig(Config.class);
        // reconfigure logger after config initialization
        configureLogger();
        LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);

        if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) {
            throw new ExceptionInInitializerError("`agent.service_name` is missing.");
        } else {
            if (StringUtil.isNotEmpty(Config.Agent.NAMESPACE) || StringUtil.isNotEmpty(Config.Agent.CLUSTER)) {
                Config.Agent.SERVICE_NAME = StringUtil.join(
                    SERVICE_NAME_PART_CONNECTOR,
                    Config.Agent.SERVICE_NAME,
                    Config.Agent.NAMESPACE,
                    Config.Agent.CLUSTER
                );
            }
        }
        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;
    }

主要流程

1、加载配置文件
2、通过系统变量重新设置相关配置
3、通过启动参数重新设置相关配置
4、初始化配置
5、重新设置日志类型
6、做一些配置信息的检查及容错

加载配置文件
private static InputStreamReader loadConfig() throws AgentPackageNotFoundException, ConfigNotFoundException {
// 获取是否存在 SPECIFIED_CONFIG_PATH 系统变量,这个变量用于设置配置文件路径,
// 如果存在查看这个变量的值是否为空,非空加载该路径下的文件;空的话加载默认路径(/config/agent.config)下的文件
// 所以可能存在有些场景下需要将配置文件放在指定位置,那么可以通过这种方式设置
        String specifiedConfigPath = System.getProperty(SPECIFIED_CONFIG_PATH);
        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.");
    }
    

其中 AgentPackagePath.getPath() 的作用是用于定位出 skywalking-agent.jar包的路径,因为知道了它的路径,那么其他的一些包的路径也就知道了,因为在默认情况下打包后的目录结构是固定的。

通过系统变量重新设置相关配置

private static void overrideConfigBySystemProp() {
        Properties systemProperties = System.getProperties();
        for (final Map.Entry<Object, Object> prop : systemProperties.entrySet()) {
            String key = prop.getKey().toString();
            if (key.startsWith(ENV_KEY_PREFIX)) {
                String realKey = key.substring(ENV_KEY_PREFIX.length());
                AGENT_SETTINGS.put(realKey, prop.getValue());
            }
        }
    }

如果系统中设置了相关的gaent配置,那么就进行替换。

初始化配置

public static void initializeConfig(Class configClass) {
        if (AGENT_SETTINGS == null) {
            LOGGER.error("Plugin configs have to be initialized after core config initialization.");
            return;
        }
        try {
        // 将 Properties 内的值赋值给 Config ,这里 Config 内的属性是以模块+配置的形式设计的,同样 配置文件中也是以模块+配置的形式设计的,不同的是配置文件内的属性都是小写的。只要将大小写相互转化就可以找到相互的映射关系
            ConfigInitializer.initialize(AGENT_SETTINGS, configClass);
        } catch (IllegalAccessException e) {
            LOGGER.error(e,
                         "Failed to set the agent settings {}"
                             + " to Config={} ",
                         AGENT_SETTINGS, configClass
            );
        }
    }
    
重新设置日志类型
static void configureLogger() {
        switch (Config.Logging.RESOLVER) {
            case JSON:
                LogManager.setLogResolver(new JsonLogResolver());
                break;
            case PATTERN:
            default:
                LogManager.setLogResolver(new PatternLogResolver());
        }
    }

这里会根据配置中设置的日志格式进行设置

配置信息的检查及容错
// 服务名是必须的,因为这涉及到服务注册
if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) {
            throw new ExceptionInInitializerError("`agent.service_name` is missing.");
        } else {
        // 命名空间也是必须的,这也涉及到服务注册
            if (StringUtil.isNotEmpty(Config.Agent.NAMESPACE) || StringUtil.isNotEmpty(Config.Agent.CLUSTER)) {
                Config.Agent.SERVICE_NAME = StringUtil.join(
                    SERVICE_NAME_PART_CONNECTOR,
                    Config.Agent.SERVICE_NAME,
                    Config.Agent.NAMESPACE,
                    Config.Agent.CLUSTER
                );
            }
        }
        // 后端地址也是必须的,这涉及到服务注册和心跳,因为数据上报可以通过kafka,所以数据上报可以不受他的影响
        if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) {
            throw new ExceptionInInitializerError("`collector.backend_service` is missing.");
        }
        // 因为peer地址一般都大于3,所以如果设置的太小会强制改为200
        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;
        }
解答

大家应该看到了,在加载配置的代码里面加载完配置后会重新设置日志类型,这个时候新的日志类型可能和原先刚开始的日志类型不一致,所以需要在最外面重新获取一次日志类型,不然日志类型还是原先skywalking默认的日志类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值