Java 在某些课程中关闭其他库的 logback 日志记录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19967244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 21:54:37  来源:igfitidea点击:

Turn off logback logging for other libraries while in certain class

javaspringloggingscheduled-taskslogback

提问by johnktims

I am successfully using Spring's @Scheduled annotation to execute a method every few seconds. The only issue is that I get a lot of log messages about transactions, etc from Hibernate and Spring because of this method.

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

I want to keep the logging levels the same because I like to receive this information for other transactions in the application.

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

Is there a way in logback to temporarily suppress another library's logging while a specific method is executing?

在执行特定方法时,logback 是否有办法暂时禁止另一个库的日志记录?

采纳答案by durron597

Yes this can be done on a per-thread basis.

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

You need to use Filtersand MDC (Mapped Diagnostic Context). This solution will onlyaffect the logging that occurs on the thread that is executing the @Scheduledmethod.

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

Overview of steps

步骤概述

  1. In your @Scheduledmethod, add an entry to the MDC of that thread.
  2. Create an implementation of ch.qos.logback.core.filter.Filter<ILoggingEvent>, which will return FilterReply.DENYif that entry is set in the MDC
  3. Add a reference to that filter in your <appender>entry in logback.xml
  1. 在您的@Scheduled方法中,向该线程的 MDC 添加一个条目。
  2. 创建 的实现ch.qos.logback.core.filter.Filter<ILoggingEvent>FilterReply.DENY如果在 MDC 中设置了该条目,它将返回
  3. 在您的<appender>条目中添加对该过滤器的引用logback.xml

Step 1

第1步

Make your @Scheduledmethod look like this:

让你的@Scheduled方法看起来像这样:

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

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

I should mention that removing the key is important because Spring may reuse the thread and the MDC would keep the value otherwise.

我应该提到删除键很重要,因为 Spring 可能会重用线程,否则 MDC 会保留该值。

Step 2

第2步

Your filter should look something like this:

您的过滤器应如下所示:

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;
    }
  }
}

Step 3

第 3 步

Add the following to your logback.xml

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

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

回答by Warren Dew

Yes: you can set loggers' log levels dynamically, and thus change it over time.

是的:您可以动态设置记录器的日志级别,从而随着时间的推移更改它。

Ideally all you will need to do is get the logger at the top of the relevant class hierarchy and set the log level to whatever you want. For example, with hibernate:

理想情况下,您需要做的就是将记录器置于相关类层次结构的顶部,并将日志级别设置为您想要的任何级别。例如,使用休眠:

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;

// When you want to temporarily change the log level
Logger orgHibernateLogger = LoggerFactory.getLogger("org.hibernate");
Level oldLogLevel = orgHibernateLogger.getLevel();
orgHibernateLogger.setLevel(Level.ERROR); // or whatever level you want

// When you want to return to the old log level
orgHibernateLogger.setLevel(oldLogLevel);

This should work as long as no other loggers in the relevant hierarchy have explicitly configured log levels. If other loggers in the hierarchy have explicitly configured log levels, you'll have to temporarily adjust all the explicitly set log levels, and then return them all to "normal" at the end.

只要相关层次结构中的其他记录器没有明确配置日志级别,这应该可以工作。如果层次结构中的其他记录器已显式配置日志级别,则您必须临时调整所有显式设置的日志级别,然后最后将它们全部恢复为“正常”。

Note that this is a time based approach, not a context based approach: if some other piece of code simultaneously uses the library while your temporary log level is in use, it will also get that temporary log level. Log levels only return to "normal" when you return then to normal. I don't think there's a simple way to avoid that without preventing the other code from running while you are using your temporary log level.

请注意,这是一种基于时间的方法,而不是基于上下文的方法:如果在使用临时日志级别时其他一些代码同时使用该库,它也会获得该临时日志级别。当您恢复正常时,日志级别只会恢复到“正常”。我认为没有一种简单的方法可以避免这种情况,而不会在您使用临时日志级别时阻止其他代码运行。

Edit: See the answer by Durron597 for a method that allow turning off the unwanted logging in the desired thread only. It's slightly less simple, but it looks like it should work.

编辑:请参阅 Durron597 的答案,了解仅允许关闭所需线程中不需要的日志记录的方法。它稍微不那么简单,但看起来它应该可以工作。

回答by gyanu

Generally logging framework supports packagelevel log configuration. You could do something like below in your logback.xmlfile:

通常日志框架支持级别的日志配置。您可以在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>

In jboss application server, we have same issue previously and filtered unwantedlog with package level log configuration as below:

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> 

As you are interested in suppressing library's log in specific method you will have to do it programmatically and restore on exit. But i am not sure if it will affect the particular code block.

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

More over If your application run concurrentlythen you can use ThreadLocallike below

如果您的应用程序同时运行,那么您可以像下面这样使用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);

 }

I have similar answer here

在这里有类似的答案