log4j日志打印级别动态调整

1,为什么日志打印级别要动态调整?

  随着项目越来越大,访问量也越来越高,遇到问题时想要排查,可是日志一打开却刷的太快太快,不好排查问题,有的时候甚至因为短时间打印日志太多,严重影响了性能,这个时候日志的打印级别的动态调整就相当有必要了,在不重启项目的情况,不改动代码的情况下,通过Apollo动态配置就可以通过配置动态的调整日志的级别,可以精确到配置具体的类的日志打印级别。

 

2,动态调整的方案

  大致思路为在springboot项目启动之后,读取Apollo配置文件里的配置文件,总共有两个,一个是总的日志级别,一个是单独的类的配置,然后设置总的之后再设置具体到类的自定义的,同时注册一个监听器监听两个文件的变化,一旦有变化就重新设置一遍,是不是很简单呢?

  具体代码如下,将该类在启动时注册入spring容器就行。值得注意的是该类中的initCustomClass()方法,该方法是因为有很多类没有在springboot启动时没有初始化,那么也就没有注册入

LoggerContext的属性中,所以是无法设置的,通过手动初始化该类的形式来初始化之后重新设置一遍。在详细的配置文件中是支持正则表达式来匹配的。

@Service @Slf4j public class LoggerConfiguration implements ConfigChangeListener, ApplicationListener<ContextRefreshedEvent> { private static final String LOGGER_LEVEL = "logger_level"; private static final String LOGGER_LEVEL_DETAIL = "logger_level_detail"; private static final String DEFAULT_LEVEL = "error"; private static final String INFO_LEVEL = "info"; private Config applicationConfig; public LoggerConfiguration(Config applicationConfig) { this.applicationConfig = applicationConfig; } @Override public void onChange(ConfigChangeEvent changeEvent) { if (changeEvent.changedKeys().contains(LOGGER_LEVEL)) { String newValue = changeEvent.getChange(LOGGER_LEVEL).getNewValue(); try { log.info("update rootLoggerLevel {}", newValue); setRootLoggerLevel(newValue); } catch (Exception e) { log.error("loggerLevel onChange failed {}", ExceptionUtil.stacktraceToString(e)); } } if (changeEvent.changedKeys().contains(LOGGER_LEVEL_DETAIL)) { String newValue = changeEvent.getChange(LOGGER_LEVEL_DETAIL).getNewValue(); try { log.info("update loggerLevel detail {}", newValue); parseLoggerConfig(newValue); } catch (Exception e) { log.error("loggerLevel detail onChange failed {}", ExceptionUtil.stacktraceToString(e)); } } } @Override public void onApplicationEvent(ContextRefreshedEvent event) { try { // 初始化风控监听action配置 String level = applicationConfig.getProperty(LOGGER_LEVEL, DEFAULT_LEVEL); log.info("init root loggerLevel {}", level); setRootLoggerLevel(level); // 注册配置监听 applicationConfig.addChangeListener(this); } catch (Exception e) { log.error("loggerLevel init failed {}", ExceptionUtil.stacktraceToString(e)); } } /** * 将未注册进日志容器的类处初始化 * * @param className */ private boolean initCustomClass(String className) { try { Class.forName(className); return true; } catch (Exception e) { log.error("init {} failed", className); return false; } } private void setRootLoggerLevel(String level) { try { Level newLevel = Level.valueOf(level); LoggerContext logContext = LoggerContext.getContext(false); Configuration configuration = logContext.getConfiguration(); LoggerConfig loggerConfig = configuration.getRootLogger(); loggerConfig.setLevel(newLevel); logContext.updateLoggers(); //update后会覆盖定制化的 setLoggerLevel(this.getClass().getName(), INFO_LEVEL); reConfig(); log.info("update rootLoggerLevel {}", level); } catch (Exception e) { log.error("setRootLoggerLevel failed {}", ExceptionUtil.stacktraceToString(e)); } } private void setLoggerLevel(String name, String level) { try { Level newLevel = Level.valueOf(level); LoggerContext logContext = LoggerContext.getContext(false); //是否没有匹配到 boolean flag = false; if (logContext.hasLogger(name)) { //精确匹配 Logger logger = logContext.getLogger(name); logger.setLevel(newLevel); log.info("update {} logger level {}", name, level); flag = true; } else { //正则匹配 Collection<Logger> loggers = logContext.getLoggers(); for (Logger logger : loggers) { if (Pattern.matches(name, logger.getName())) { logger.setLevel(newLevel); log.info("update {} logger level {}", name, level); flag = true; } } } //该类未注册就注册,注册失败那么也就不再继续设置 if (!flag && initCustomClass(name)) { //初始化未注册的类 setLoggerLevel(name, level); } } catch (Exception e) { log.error("setLoggerLevel failed {}", ExceptionUtil.stacktraceToString(e)); } } private void reConfig() { String detail = applicationConfig.getProperty(LOGGER_LEVEL_DETAIL, ""); if (StringUtils.isNotEmpty(detail)) { parseLoggerConfig(detail); } } private void parseLoggerConfig(String value) { Map<String, String> config = JSON.parseObject(value, Map.class); if (config == null) { return; } config.forEach((k, v) -> setLoggerLevel(k, v)); } public void setApplicationConfig(Config applicationConfig) { this.applicationConfig = applicationConfig; } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppjsz.html