背景
代码中添加了一些日志,只有在问题排查&过程跟踪时,才需要打印出来,其他时间不需要打印出来。
方案
- 写一个
通用的Logger类
,以及一个"日志级别"配置项,打印日志时,调用logger.log
方法,方法内部通过判断日志级别来分别调用log.debug
、log.info
等方法。 - 打印日志方法不变(业务代码自己直接调用
log.debug
、log.info
等方法),通过配置来动态修改指定业务类内的log
对象的日志级别。
以上的方案1:通用的Logger类
要把log
的所有方法(log.debug
、log.info
等)都覆盖到,需要写很多个方法,太麻烦。
方案2:可以做到精细化管理,并且不需要对原先的代码做修改。
那假如不想管到那么精细,只想用通用的Logger类
来简单管理呢?
实现
方案1
借鉴了以上方案2的核心代码:
@Slf4j @Component public class DynamicLogger { /** * @param dynamicLevel * @author * @date 2022/12/6 15:09 */ @Value("${log.dynamic.level:WARN}") // 通过配置系统配置和修改,也可以通过其他方式,但是核心代码一样 public void setDynamicLevel(String dynamicLevel) { log.info("[动态日志]收到日志级别配置[{}]", dynamicLevel); try { String logType = StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr(); if ("org.apache.logging.slf4j.Log4jLoggerFactory".equals(logType)) { LoggerContext.getContext(false) .getLogger(DynamicLogger.class.getName()) .setLevel(Level.toLevel(dynamicLevel)); } if (xxx) { // logback等其他日志组件 } else { log.error("[动态日志]Log框架类别[{}]无法识别: type{}", logType); } } catch (Exception e) { log.error("[动态日志]日志级别配置[{}]解析异常!", dynamicLevel, e); } } /** * @return org.slf4j.Logger * @author * @date 2022/12/6 15:35 */ public static Logger getLogger() { return log; } }
使用时,从原先的
log.info
改为DynamicLogger.getLogger.info
。- 写一个通用的Logger类,以及一个"日志级别"配置项,打印日志时,从Logger类获取实际执行调用
logger.log
方法,方法内部通过判断日志级别来动态修改当前log
对象的打印级别。
方案2
以上方案,需要对底层是使用哪个日志组件做判断,如果是使用Springboot
框架,则Springboot
提供了更上一层的抽象:
@Autowired
private LoggingSystem loggingSystem;
public void setDynamicLevel(String dynamicLevel, String loggerName) {
log.info("[动态日志]收到日志级别配置[{}]", dynamicLevel);
try {
LoggerConfiguration loggerConfiguration = loggingSystem.getLoggerConfiguration(loggerName);
if (loggerConfiguration == null) {
log.error("[动态日志]没有获取到[{}]日志配置", loggerName);
return;
}
List<String> supportLevels = loggingSystem.getSupportedLogLevels().stream().map(Enum::name).collect(Collectors.toList());
if (!supportLevels.contains(dynamicLevel)) {
log.error("[动态日志]不支持配置的[{}]日志级别", dynamicLevel);
return;
}
if (!loggerConfiguration.getEffectiveLevel().name().equals(dynamicLevel)) {
loggingSystem.setLogLevel(loggerName, LogLevel.valueOf(dynamicLevel));
} else {
log.info("[动态日志]当前已经是配置的[{}]日志级别", dynamicLevel);
}
} catch (Exception e) {
log.error("[动态日志]日志级别配置[{}]解析异常!", dynamicLevel, e);
}
}
但是这方案也有局限性,就是只能修改配置的Logger
(比如xml文件里配置的Logger列表)。比如不能单独修改某个类下的Logger对象(比如不能像方案1
那样修改的DynamicLogger
类下的log
对象的打印级别),只能修改配置Loggers
里的Logger
的级别,例子:如果项目用的是以下log4j2.xml
文件,那loggerName
只能是com.xxx
或者ROOT
。
<Configuration status="DEBUG" updateCheck="false">
……
<Loggers>
<Logger name="com.xxx" level="INFO" additivity="false">
<AppenderRef ref="InfoRollingFile" />
</Logger>
<Root level="INFO">
<AppenderRef ref="Console" />
<AppenderRef ref="InfoRollingFile" />
</Root>
</Loggers>
</Configuration>
对比
以上两个方案,调整的对象是互相反过来的。
- 方案1:调整的是日志类的级别,如果将级别调整到XML配置的级别以下,就不会有日志;调整到配置的级别以上,就会有日志。
- 方案2:调整的是XML配置的级别,将级别调整到日志类的打印级别以下,就会有日志;调整到日志类的打印级别以上,就不会有日志。
参考:
Java日志:日志级别动态调整
https://juejin.cn/post/7140939233518649357
求你了,别再随便打日志了,教你动态修改日志级别!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。