基于Apollo动态修改日志级别

目录

前言

一、日志的自动配置过程

二、动态修改日志级别

1.日志修改类

 2.Apollo监听器

总结


前言

       昨天组内有人反映说系统的日志级别在Apollo中配置了没有生效,在默认的properties文件中配置了会生效,这就有点意思了。在前面的文章中我们分析过,Apollo属性的优先级是高于properties文件,如果二者同时存在,应该以Apollo中的属性为准,那么最有可能的是在该属性作用的位置,Apollo属性还没有加载进来,默认的properties文件已经加载。


一、日志的自动配置过程

          springboot实现了日志的自动装配,在factory文件中引入了LoggingApplicationListener和ClasspathLoggingApplicationListener两个类,主要的配置逻辑在LoggingApplicationListener中。

public class LoggingApplicationListener implements GenericApplicationListener {
	private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
		if (this.loggingSystem == null) {
			this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
		}
		initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
	}
}
	protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
	
		initializeSystem(environment, this.loggingSystem, this.logFile);
		//初始化最终的日志级别
		initializeFinalLoggingLevels(environment, this.loggingSystem);
		registerShutdownHookIfNecessary(environment, this.loggingSystem);
	}
	private void initializeFinalLoggingLevels(ConfigurableEnvironment environment, LoggingSystem system) {
		bindLoggerGroups(environment);
		if (this.springBootLogging != null) {
			initializeLogLevel(system, this.springBootLogging);
		}
		//设置级别
		setLogLevels(system, environment);
	}

          根据日志的级别配置位置,如果Apollo正常配置,此时应该已经加载进来。

       我们项目中只配置了Apollo.bootstrap.enabled,没有配置Apollo.bootstrap.eagerLoad.enabled,所以不能在postProcessEnvironment方法中初始化,最终初始化的调用过程如下

  prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);
  applyInitializers(context);
  public void initialize(ConfigurableApplicationContext context) {
    ConfigurableEnvironment environment = context.getEnvironment();
    //环境中是否配置apollo.bootstrap.enabled=true,由于
    String enabled = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "false");
    if (!Boolean.valueOf(enabled)) {
      logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED);
      return;
    }
    logger.debug("Apollo bootstrap config is enabled for context {}", context);

    initialize(environment);
  }

       由于配置上的问题,导致项目中会先初始化日志级别,再加载Apollo配置,导致Apollo配置的日志级别失效。所以,如果想让Apollo配置的日志级别在程序开始运行时生效,只需要配置Apollo.bootstrap.eagerLoad.enabled和Apollo.bootstrap.enabled,在日志初始化之前加载Apollo配置,但还没有实现动态修改日志级别。

二、动态修改日志级别

        Apollo的配置修改之后不会影响日志级别,因为程序中没有属性对相关配置监听,配置修改之后,程序不会做出应对。所以程序的设计思路很明确,自定义一个Apollo监听器,当日志级别相关的配置修改时,手动修改程序中的日志级别,无需重启。

1.日志修改类

       创建一个类能够调用loggingSystem的方法,修改日志级别。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggerConfiguration;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Component
public class LoggerLevelSettingService {

    @Autowired
    private LoggingSystem loggingSystem;

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggerLevelSettingService.class);

    public void setRootLoggerLevel(String level,String loggerName) {

        LoggerConfiguration loggerConfiguration = loggingSystem.getLoggerConfiguration(loggerName);

        if (loggerConfiguration == null) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("no loggerConfiguration with loggerName " + level);
            }
            return;
        }

        if (!supportLevels().contains(level)) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("current Level is not support : " + level);
            }
            return;
        }

        if (!loggerConfiguration.getEffectiveLevel().equals(LogLevel.valueOf(level))) {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("setRootLoggerLevel success,old level is  '" + loggerConfiguration.getEffectiveLevel()
                        + "' , new level is '" + level + "'");
            }
            loggingSystem.setLogLevel(loggerName, LogLevel.valueOf(level));
        }
    }

    private List<String> supportLevels() {
        return loggingSystem.getSupportedLogLevels().stream().map(Enum::name).collect(Collectors.toList());
    }
}

 2.Apollo监听器

           创建Apollo监听器,当相关配置发生改变时,调用修改类的方法,修改日志级别。

@Service
public class ValidateService {
    private static final Logger logger = LoggerFactory.getLogger(ValidateService.class);
    @Autowired
    LoggerLevelSettingService loggerLevelSettingService;

    @Value("${logging.level.com.ctrip.framework.apollo.demo.controller}")
    private String controllerLevel;

    @ApolloConfigChangeListener
    private void someChangeHandler(ConfigChangeEvent changeEvent) {
        if (changeEvent.isChanged("logging.level.com.ctrip.framework.apollo.demo.controller")) {
            loggerLevelSettingService.setRootLoggerLevel(changeEvent.getChange("logging.level.com.ctrip.framework.apollo.demo.controller").getNewValue().toUpperCase(),
                    "com.ctrip.framework.apollo.demo.controller");
        }
    }

}


总结

        本文针对Apollo配置日志级别时出现的问题进行分析,最后提出动态修改日志级别的解决方法,代码进行了部分删减,仅提供思路,尚需完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值