自由屋推书网—热门的小说推荐平台!

你的位置: 首页 > apache

结合Apollo配置中心实现日志级别动态配置

2022-01-08 10:41:21

目前常用的实现动态配置日志级别的应该非SpringBoot的spring-boot-starter-actuator莫属了。不过通过spring-boot-starter-actuator配置的日志级别,服务一旦重启就会恢复原状。且只能通过访问指定的接口来修改单个实例的日志级别(SpringBootAdmin也是一样,只能修改单个实例的)。如果是想修改某个服务所有实例的日志级别,只能修改配置文件,然后重启服务,可以说局限性稍微大点儿。

由于重启服务太费劲儿,所以想到了利用Apollo配置中心来动态修改日志级别。

实现的大体思路是通过Apollo的监听机制,结合Spring的事件监听,来刷新日志级别。

具体代码如下:

LogLevelRefreshEvent:自定义Spring事件。

  1. import lombok.ToString;
  2. import org.springframework.context.ApplicationEvent;
  3. /**
  4.  * @author lifengdi
  5.  * @date 2021/12/24 11:29
  6.  */
  7. @ToString
  8. public class LogLevelRefreshEvent extends ApplicationEvent {
  9.     /**
  10.      * key
  11.      */
  12.     private final String key;
  13.     /**
  14.      * 旧值
  15.      */
  16.     private final Object oldValue;
  17.     /**
  18.      * 新值
  19.      */
  20.     private final Object newValue;
  21.     public LogLevelRefreshEvent(String key, Object oldValue, Object newValue) {
  22.         super(key);
  23.         this.key = key;
  24.         this.oldValue = oldValue;
  25.         this.newValue = newValue;
  26.     }
  27.     public String getKey() {
  28.         return key;
  29.     }
  30.     public Object getOldValue() {
  31.         return oldValue;
  32.     }
  33.     public Object getNewValue() {
  34.         return newValue;
  35.     }
  36. }

LogConfig:日志级别配置文件,用于获取Apollo配置以及转换日志级别。

  1. import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
  2. import lombok.Getter;
  3. import org.springframework.boot.logging.LogLevel;
  4. import org.springframework.context.annotation.Configuration;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. /**
  8.  * @author lifengdi
  9.  * @date 2021/12/24 14:29
  10.  */
  11. @Configuration
  12. @Getter
  13. public class LogConfig {
  14.     /**
  15.      * 日志级别配置key
  16.      */
  17.     public static final String LOG_LEVEL_CONFIG_KEY = "logLevel.list";
  18.     /**
  19.      * 日志级别配置,格式:
  20.      * <code>
  21.      * {
  22.      *     "com.cowell.conveyor": "warn",
  23.      *     "com.cowell.tools": "warn"
  24.      * }
  25.      * </code>
  26.      */
  27.     @ApolloJsonValue("${logLevel.list:{}}")
  28.     private Map<String, String> logLevelConfig;
  29.     /**
  30.      * 日志级别映射
  31.      */
  32.     private final Map<String, LogLevel> levelMap = new HashMap<String, LogLevel>() {
  33.         {
  34.             put("trace", LogLevel.TRACE);
  35.             put("debug", LogLevel.DEBUG);
  36.             put("info", LogLevel.INFO);
  37.             put("warn", LogLevel.WARN);
  38.             put("error", LogLevel.ERROR);
  39.             put("fatal", LogLevel.FATAL);
  40.             put("off", LogLevel.OFF);
  41.         }
  42.     };
  43.     public Map<String, LogLevel> getLevelMap() {
  44.         return levelMap;
  45.     }
  46.     /**
  47.      * 根据名称获取日志级别,默认返回debug级别。
  48.      * @param logLevel 级别名称
  49.      * @return 日志级别 {@link LogLevel}
  50.      */
  51.     public LogLevel getFromLevelMap(String logLevel) {
  52.         return levelMap.getOrDefault(logLevel, LogLevel.DEBUG);
  53.     }
  54. }

LogLevelUtils:工具类

  1. import com.lifengdi.config.LogConfig;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.boot.logging.LoggerConfiguration;
  5. import org.springframework.boot.logging.LoggingSystem;
  6. import java.util.List;
  7. import java.util.Map;
  8. /**
  9.  * @author lifengdi
  10.  * @date 2021/12/27 17:44
  11.  */
  12. public class LogLevelUtils {
  13.     private static final Logger logger = LoggerFactory.getLogger(LogLevelUtils.class);
  14.     /**
  15.      * 动态刷新日志级别
  16.      * @param loggingSystem LoggingSystem
  17.      * @param logConfig LogConfig
  18.      */
  19.     public static void refreshLogLevel(LoggingSystem loggingSystem, LogConfig logConfig) {
  20.         Map<String, String> logLevelConfig = logConfig.getLogLevelConfig();
  21.         List<LoggerConfiguration> loggerConfigurations = loggingSystem.getLoggerConfigurations();
  22.         if (!logLevelConfig.isEmpty()) {
  23.             logLevelConfig.forEach((loggerName, value) -> {
  24.                 String logLevel = value.toLowerCase();
  25.                 for (LoggerConfiguration loggerConfiguration : loggerConfigurations) {
  26.                     if (loggerConfiguration.getName().startsWith(loggerName)) {
  27.                         loggingSystem.setLogLevel(loggerName, logConfig.getFromLevelMap(logLevel));
  28.                         logger.debug("LogLevelUtils|RefreshLogLevel|SUCCESS|loggerName:{},logLevel:{}", loggerName, logLevel);
  29.                     }
  30.                 }
  31.             });
  32.         }
  33.     }
  34. }

日志级别刷新Listener:

  1. import com.lifengdi.config.LogConfig;
  2. import com.lifengdi.util.LogLevelUtils;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.boot.logging.LoggingSystem;
  6. import org.springframework.context.ApplicationListener;
  7. import org.springframework.stereotype.Component;
  8. /**
  9.  * 日志级别刷新Listener
  10.  *
  11.  * @author lifengdi
  12.  * @date 2021/12/24 11:34
  13.  */
  14. @Component
  15. @Slf4j
  16. public class LogLevelRefreshListener implements ApplicationListener<LogLevelRefreshEvent> {
  17.     @Autowired
  18.     private LoggingSystem loggingSystem;
  19.     @Autowired
  20.     private LogConfig logConfig;
  21.     @Override
  22.     public void onApplicationEvent(LogLevelRefreshEvent logLevelRefreshEvent) {
  23.         if (LogConfig.LOG_LEVEL_CONFIG_KEY.equals(logLevelRefreshEvent.getKey())) {
  24.             log.info("LogLevelRefreshListener|onApplicationEvent|refreshLogLevel|configRefreshEvent:{}", logLevelRefreshEvent);
  25.             LogLevelUtils.refreshLogLevel(loggingSystem, logConfig);
  26.             log.info("LogLevelRefreshListener|onApplicationEvent|refreshLogLevel|SUCCESS|configRefreshEvent:{}", logLevelRefreshEvent);
  27.         }
  28.     }
  29. }

服务启动时日志级别刷新Listener:

  1. import com.lifengdi.config.LogConfig;
  2. import com.lifengdi.util.LogLevelUtils;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.context.event.ApplicationReadyEvent;
  5. import org.springframework.boot.logging.LoggingSystem;
  6. import org.springframework.context.ApplicationListener;
  7. import org.springframework.stereotype.Component;
  8. /**
  9.  * 服务启动时日志级别刷新Listener
  10.  *
  11.  * @author lifengdi
  12.  * @date 2021/12/24 13:59
  13.  */
  14. @Component
  15. public class LogLevelApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {
  16.     @Autowired
  17.     private LoggingSystem loggingSystem;
  18.     @Autowired
  19.     private LogConfig logConfig;
  20.     @Override
  21.     public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
  22.         LogLevelUtils.refreshLogLevel(loggingSystem, logConfig);
  23.     }
  24. }
  25. 增加事件发布:
  26. @Component
  27. public class ApolloAutoRefreshBean {
  28.     private final Logger logger = LoggerFactory.getLogger(ApolloAutoRefreshBean.class);
  29.     @Autowired
  30.     private ApplicationContext applicationContext;
  31.     @ApolloConfigChangeListener
  32.     public void onChange(ConfigChangeEvent changeEvent) {
  33.         logger.info("ApolloAutoRefreshBean|onChange|apollo触发变更|param:namespace={}", changeEvent.getNamespace());
  34.         for (String key : changeEvent.changedKeys()) {
  35.             ConfigChange change = changeEvent.getChange(key);
  36.             logger.info("ApolloAutoRefreshBean|onChange|apollo数据key-value发生变更|key: {}, oldValue: {}, newValue: {}, changeType: {}",
  37.                     change.getPropertyName(), change.getOldValue(), change.getNewValue(),
  38.                     change.getChangeType());
  39.             applicationContext.publishEvent(new LogLevelRefreshEvent(key, change.getOldValue(), change.getNewValue()));
  40.         }
  41.         applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
  42.     }
  43. }

配置中心配置的参数格式如下:

  1. {
  2.     "com.lifengdi.util""info",
  3.     "com.lifengdi.tools""warn"
  4. }

至此,动态配置日志级别算是搞定了。(转载自:李锋镝的博客)

编辑推荐

热门小说