如何将Spring Boot logger设置为仅计划任务?

时间:2020-08-12 15:17:48

标签: 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

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

但是我还有一个预定的任务,每秒钟运行一次,如下所示:

@Scheduled(cron = "${* * * * * *}")
public void task() {
  ...
}

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

我如何设置记录器来执行此操作?谢谢。

4 个答案:

答案 0 :(得分: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");
  }
}

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

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

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

  </appender>

SampleFilter:

public class SampleFilter extends Filter<ILoggingEvent> {

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

答案 1 :(得分: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));
  }
}

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

从功能上讲,它可以轻松地在不同的上下文中重用:如果需要,您可以为此创建一个方面,例如,从此需求中释放业务逻辑。

修改

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

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

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

答案 2 :(得分:2)

我认为您将无法实现目标。

即使您在运行时设法关闭hibernate的日志记录级别,它也将hibernate在应用程序中全局关闭日志级别,因为它与调用者类加载器相关联

这意味着如果存在要在第一个同步执行中登录的休眠调用的并发执行,而又不想在第二个并发异步执行中进行登录,则它们将相互干扰,并且您将获得不确定的结果

答案 3 :(得分:0)

我的答案受到了GreyFairer的启发。

实际上,默认情况下,StringBoot使用logback,因此如果尚未用log4j覆盖,则只需创建

logback-spring.xml

并放入类路径(WEB-INF / classes) 取自http://logback.qos.ch/manual/filters.html

的示例

logback-spring.xml

    <?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">      
      <evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator"> 
        <expression>
           (e.mdc?.get("DONOTLOG") =~ /true/ )
        </expression>
      </evaluator>
      <OnMismatch>NEUTRAL</OnMismatch>
      <OnMatch>DENY</OnMatch>
    </filter>
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger - %msg%n
      </pattern>
    </encoder>
  </appender>

  <logger name="org.hibernate.sql" level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>
 </configuration>

然后

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

应该解决目的。

相关问题