如何仅将spring boot logger设置为计划任务?

dan*_*tis 6 java spring spring-boot

我有一个 spring boot 项目,所以我设置了休眠记录器来记录请求中的所有查询,如下所示:

在我的 application.properties 文件中

logging.level.org.hibernate.type=trace
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=trace
Run Code Online (Sandbox Code Playgroud)

这很好用,我的所有请求都显示了休眠查询的日志。

但我也有一个计划任务,每秒钟运行一次,如下所示:

@Scheduled(cron = "${* * * * * *}")
public void task() {
  ...
}
Run Code Online (Sandbox Code Playgroud)

因此,我想仅为此任务执行关闭休眠查询日志,以避免弄乱我的请求输出日志。

我怎样才能设置记录器来做到这一点?!谢谢。

Gee*_*nte 7

如果您使用 Slf4j 和 logback,则可以根据映射的诊断上下文 ( http://logback.qos.ch/manual/mdc.html )进行过滤。

MDC 是线程本地的,您可以将要在记录器中使用的任何键值对放入其中。例如:

@Scheduled(cron = "${* * * * * *}")
public void task() {
  MDC.put("DONOTLOG", "true")
  try {
    ....
  } finally {
    MDC.remove("DONOTLOG");
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以在自定义 logback 过滤器 ( http://logback.qos.ch/manual/filters.html ) 中使用它,方法是将它放在 logback.xml 中:

<configuration>
  <appender name="...">

    <filter class="...SampleFilter" />

  </appender>
Run Code Online (Sandbox Code Playgroud)

样品过滤器:

public class SampleFilter extends Filter<ILoggingEvent> {

  @Override
  public FilterReply decide(ILoggingEvent event) {    
    if (event.getMDCPropertyMap().containsKey("DONOTLOG")) {
      return FilterReply.DENY;
    } else {
      return FilterReply.NEUTRAL;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


jcc*_*ero 2

我假设你正在使用 Slf4j。

该库不支持开箱即用的功能。

在运行时更改记录器级别的能力很大程度上取决于配置的底层日志库(Logback、Log4J2 等)。

但是 Spring Boot 提供了一个底层日志系统来为我们处理所有这些事情。我们可以使用底层日志系统来实现您需要的功能。

您可以执行类似以下示例的操作:

@Scheduled(cron = "${* * * * * *}")
public void task() {
  // At the beginning of the method, disable logging levels
  final List<String> loggerNames = Arrays.asList("org.hibernate.SQL", "org.hibernate.type", "org.hibernate.type.descriptor.sql.BasicBinder");
Map<String, LogLevel> previousLogLevels = new HashMap();
loggerNames.forEach(loggerName -> {
  final LoggerConfiguration loggerConfiguration = loggingSystem.getLoggerConfiguration(loggerName);
  final LogLevel logLevel = loggerConfiguration.getEffectiveLevel();
  previousLogLevels.put(loggerName, logLevel);
  loggingSystem.setLogLevel(loggerName, LogLevel.OFF);
});
  
  try {
    // Do your stuff
    ...
  } finally {
    // Restore the logging levels to the original ones
    previousLogLevels.forEach((loggerName, logLevel) -> loggingSystem.setLogLevel(loggerName, logLevel));
  }
}
Run Code Online (Sandbox Code Playgroud)

您必须在计划任务 bean 中注入一个 类型的 bean LoggingSystem,以便可以在代码中引用它。

该功能可以在不同的上下文中轻松重用:如果需要,您可以为此创建一个方面,例如,将业务逻辑从这种需求中解放出来。

编辑

阅读@KavithakaranKanapathippillai 的答案并仔细阅读您的问题后,我完全理解您的需求。

他是对的:请注意,通过此设置,您将全局修改受影响日志的日志记录级别,不仅针对异步任务,而且其余代码也将受到更改的影响,因此它将始终如果“正常”代码使用 Hibernate 并在异步任务运行时执行,则可能会丢失一些“正常”应用程序代码日志跟踪。

这是否重要将在很大程度上取决于异步任务运行的数量 - 我认为如果每秒执行一次,它运行得非常快,但另一方面,它运行很多次 - 以及您的应用程序收到的事务数量。