我成功使用Spring的@Scheduled注释每隔几秒就执行一次方法。唯一的问题是,由于这种方法,我从Hibernate和Spring获得了很多关于事务的日志消息。
我想保持日志记录级别不变,因为我希望收到应用程序中其他事务的此信息。
在执行特定方法时,是否有一种方法可以在logback中暂时禁止另一个库的日志记录?
答案 0 :(得分:17)
您需要使用Filters和MDC (Mapped Diagnostic Context)。此解决方案将仅影响正在执行@Scheduled
方法的线程上发生的日志记录。
@Scheduled
方法中,向该主题的MDC添加一个条目。ch.qos.logback.core.filter.Filter<ILoggingEvent>
的实现,如果在MDC中设置了该条目,将返回FilterReply.DENY
<appender>
logback.xml
条目中添加对该过滤条的引用
醇>
让您的@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>
答案 1 :(得分:4)
通常,日志记录框架支持包级别日志配置。您可以在 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);
}
我有类似的答案here
答案 2 :(得分:3)
是的:您可以设置记录器&#39;动态记录级别,从而随时间改变它。
理想情况下,您需要做的就是将记录器放在相关类层次结构的顶部,并将日志级别设置为您想要的任何值。例如,使用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);
只要相关层次结构中没有其他记录器明确配置了日志级别,这应该可以正常工作。如果层次结构中的其他记录器已明确配置日志级别,则您必须临时调整所有显式设置的日志级别,然后将它们全部返回到&#34; normal&#34;最后。
请注意,这是一种基于时间的方法,而不是基于上下文的方法:如果在使用临时日志级别时其他一些代码同时使用该库,它也将获得该临时日志级别。日志级别仅返回&#34;正常&#34;当你返回正常。我不认为这是一种避免这种情况的简单方法,而不会在您使用临时日志级别时阻止其他代码运行。
编辑:请参阅Durron597的答案,了解允许仅关闭所需线程中不需要的日志记录的方法。它稍微不那么简单,但它看起来应该有效。