在某些类中关闭其他库的 logback 日志记录
Posted
技术标签:
【中文标题】在某些类中关闭其他库的 logback 日志记录【英文标题】:Turn off logback logging for other libraries while in certain class 【发布时间】:2013-11-26 20:22:32 【问题描述】:我成功地使用 Spring 的 @Scheduled 注解每隔几秒执行一个方法。唯一的问题是,由于这种方法,我从 Hibernate 和 Spring 收到了很多关于事务等的日志消息。
我希望保持日志记录级别相同,因为我喜欢接收应用程序中其他事务的此信息。
在执行特定方法时,是否有办法在 logback 中暂时禁止另一个库的日志记录?
【问题讨论】:
虽然有是的答案,但我很想听听一种方法来关闭特定方法/类的日志记录,这在并发应用程序中可以正常工作。 你等的好。对于并发代码,Durron597 的回答比我的好,我很高兴有机会了解它。 【参考方案1】:是的:您可以动态设置记录器的日志级别,从而随着时间的推移进行更改。
理想情况下,您需要做的就是将记录器置于相关类层次结构的顶部,并将日志级别设置为您想要的任何级别。例如,使用休眠:
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);
只要相关层次结构中没有其他记录器明确配置日志级别,这应该可以工作。如果层次结构中的其他记录器已显式配置日志级别,则您必须临时调整所有显式设置的日志级别,然后在最后将它们全部恢复为“正常”。
请注意,这是一种基于时间的方法,而不是基于上下文的方法:如果在使用您的临时日志级别时,其他一些代码同时使用该库,它也会获得该临时日志级别。只有当您恢复正常时,日志级别才会恢复为“正常”。我认为没有一种简单的方法可以避免这种情况,而不会在您使用临时日志级别时阻止其他代码运行。
编辑:请参阅 Durron597 的答案,了解一种仅允许在所需线程中关闭不需要的日志记录的方法。它稍微不那么简单,但看起来应该可以工作。
【讨论】:
你的最后一句话让我很难过:全局更改日志级别是非常脆弱的方法,尤其是在多线程应用程序的情况下(这几天很流行) 嗯,这个问题是关于“临时”而不是“针对某些线程”的。也许当有足够多的人证明需要后者时——我同意有一个——logback 团队会对此做一些事情。【参考方案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>%dISO8601 | %-5level | %thread | %logger1 | %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);
我也有类似的答案here
【讨论】:
【参考方案3】:是的,这可以在每个线程的基础上完成。
您需要使用Filters 和MDC (Mapped Diagnostic Context)。此解决方案将仅影响正在执行 @Scheduled
方法的线程上发生的日志记录。
步骤概述
-
在您的
@Scheduled
方法中,向该线程的 MDC 添加一个条目。
创建ch.qos.logback.core.filter.Filter<ILoggingEvent>
的实现,如果在MDC 中设置了该条目,它将返回FilterReply.DENY
在logback.xml
的<appender>
条目中添加对该过滤器的引用
步骤 1
使您的@Scheduled
方法如下所示:
@Scheduled(fixedRate=30000)
public void scheduledMethod ()
try
MDC.put("scheduled", "true");
// Your code here
finally
MDC.remove("scheduled");
我应该提到删除键很重要,因为 Spring 可能会重用线程,否则 MDC 会保留该值。
第二步
您的过滤器应如下所示:
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;
第三步
将以下内容添加到您的logback.xml
<appender name="myAppender" class="ch.qos.logback.core.ConsoleAppender">
<filter class="my.domain.application.logging.MDCFilter" />
<!-- the rest of your appender -->
</appender>
【讨论】:
以上是关于在某些类中关闭其他库的 logback 日志记录的主要内容,如果未能解决你的问题,请参考以下文章
在 Google App Engine 应用程序中关闭控制台日志记录
如何在 selenium 3 中关闭 Marionette/gecko 驱动程序日志