在特定类中关闭其他库的日志是的,这可以在每个线程的基础上完成。

2022-09-02 20:33:05

我成功地使用Spring的@Scheduled注释每隔几秒钟执行一个方法。唯一的问题是,由于这种方法,我从Hibernate和Spring获得了很多关于交易等的日志消息。

我希望保持日志记录级别不变,因为我喜欢接收应用程序中其他事务的此信息。

有没有办法在日志中临时禁止另一个库的日志记录,而特定方法正在执行?


答案 1

是的,这可以在每个线程的基础上完成。

需要使用筛选器MDC(映射的诊断上下文)。此解决方案将仅影响在执行该方法的线程上发生的日志记录。@Scheduled

步骤概述

  1. 在您的方法中,向该线程的 MDC 添加一个条目。@Scheduled
  2. 创建 的实现,如果在 MDC 中设置了该条目,该实现将返回ch.qos.logback.core.filter.Filter<ILoggingEvent>FilterReply.DENY
  3. 在条目中添加对该筛选器的引用<appender>logback.xml

步骤1

使方法如下所示:@Scheduled

@Scheduled(fixedRate=30000)
public void scheduledMethod () {
    try{
        MDC.put("scheduled", "true");

        // Your code here
    }finally{
        MDC.remove("scheduled");
    }
}

我应该提到删除密钥很重要,因为Spring可能会重用线程,而MDC将保留该值。

第 2 步

您的过滤器应如下所示:

package my.domain.application.logging;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class MDCFilter extends Filter<ILoggingEvent> {

  @Override
  public FilterReply decide(ILoggingEvent event) {    
    String scheduled = event.getMDCPropertyMap().get("scheduled");
    if ("true".equals(scheduled)) {
      return FilterReply.DENY;
    } else {
      return FilterReply.NEUTRAL;
    }
  }
}

第 3 步

将以下内容添加到您的logback.xml

<appender name="myAppender" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="my.domain.application.logging.MDCFilter" />
    <!-- the rest of your appender -->
</appender>

答案 2

通常,日志记录框架支持级日志配置。您可以在 logback.xml 文件中执行如下操作:

<configuration>
    <logger name="org.hibernate.transaction" level="OFF"/>   // change log level to suppress here
     <logger name="org.springframework.transaction" level="OFF"/>

    <root level="ALL">
        <appender class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{ISO8601} | %-5level | %thread | %logger{1} | %m%n</pattern>
            </encoder>
        </appender>
    </root>
</configuration>

jboss 应用程序服务器中,我们之前遇到过同样的问题,并使用包级日志配置过滤不需要的日志,如下所示:

<logger category="com.lftechnology.sbworkbench">
    <level name="DEBUG"/>
</logger>
<logger category="org.quartz">
    <level name="WARN"/>
</logger>
<logger category="com.liferay.portal">
    <level name="INFO"/>
</logger>
<logger category="org.jboss.as.server.deployment">
    <level name="ERROR"/>
</logger> 

由于您对以特定方法抑制库的日志感兴趣,因此您必须以编程方式执行此操作并在退出时恢复。但我不确定它是否会影响特定的代码块。

更多内容 如果您的应用程序同时运行那么您可以使用 ThreadLocal,如下所示

public Class A implements Runnable {
    //you can later dynamically configure this variable also
    private static final ThreadLocal<Logger> CLASS_LOGGER = new ThreadLocal<Logger>(){
       Logger LOGGER = LoggerFactory.getLogger(A.class);
         return LOGGER;
       }

     @Override
 public void run() {
   //before calling your function change log level
   //as we declare local variable here this most likely  to affect log here only
   Logger Logger = LoggerFactory.getLogger("org.hibernate.transaction");
   Level oldLogLevel = Logger.getLevel(); 
   Logger.setLevel(Level.OFF); // 

   callYourFunction();

   //restore log level to previous
   Logger.setLevel(oldLogLevel);

 }

我在这里也有类似的答案


推荐