您现在的位置是:网站首页 > 代码编程 > JAVA开发JAVA开发

【原】为什么说在log4j中Threshold拥有最高优先级

不忘初心 不忘初心 2020-09-18 围观() 评论() 点赞() JAVA开发

简介:在很早的时候,我在博客上专门写过几篇关于log4j的文章,当时学习的时候,还特意标注了Threshold的优先级最高,没成想,看文章的学会了,写文章的人自己忘记了。。。最近这几天,我在优化博客的代码,调试的过程中,想将所有的sql日志打印出来,多么简单的事情,却没注意细节,将Threshold的日志级别配错了,导致sql打印不出来,竟然浪费了我几乎半天的时间来找问题。

在很早的时候,我在博客上专门写过几篇关于log4j的文章,当时写文章的时候,还特意标注了Threshold的优先级最高,没成想,看文章的学会了,写文章的人自己忘记了。。。

最近这几天,我在优化博客的代码,调试的过程中,想将所有的sql日志打印出来,多么简单的事情,却没注意细节,将Threshold的日志级别配错了,导致sql打印不出来,竟然浪费了我几乎半天的时间来找问题。

我的配置文件(log4j.properties)如下:

log4j.rootLogger=INFO,console

# framework
log4j.logger.org.springframework=ERROR
log4j.logger.org.apache.ibatis=ERROR
log4j.logger.org.mybatis.spring=ERROR
log4j.logger.com.mchange.v2=ERROR

# self
log4j.logger.com.wolffy=DEBUG

# sql
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=INFO
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c - %m%n

大家觉着上述配置,能打印出来sql日志吗?

有人可能会想,你开篇都这么说了,肯定是打印不出来呀!!!

没错,这个配置确实打印不出来sql日志,大家可能会怀疑是否rootLogger在作祟,但就算是我将rootLogger直接设置为DEBUG级别都不行,后来我debug的时候发现也确实不是它,反而问题出在了Threshold上,在这里,多余的代码我就不放了,直接放点儿需要debug的关键代码,让大家明白问题出在哪里。

AppenderSkeleton.java

为什么说在log4j中Threshold拥有最高优先级

在它里面有一个doAppend()方法

/**
  * This method performs threshold checks and invokes filters before
  * delegating actual logging to the subclasses specific {@link
  * AppenderSkeleton#append} method.
  * */
public
synchronized 
void doAppend(LoggingEvent event) {
  if(closed) {
    LogLog.error("Attempted to append to closed appender named ["+name+"].");
    return;
  }
  
  if(!isAsSevereAsThreshold(event.getLevel())) {
    return;
  }
  Filter f = this.headFilter;
  
  FILTER_LOOP:
  while(f != null) {
    switch(f.decide(event)) {
    case Filter.DENY: return;
    case Filter.ACCEPT: break FILTER_LOOP;
    case Filter.NEUTRAL: f = f.getNext();
    }
  }
  
  this.append(event);    
}

紧接着,看它的isAsSevereAsThreshold()方法,问题就在这一行,我发现每次打印的sql日志,走到这一行的时候,直接就return掉了。

/**
   Check whether the message level is below the appender's
   threshold. If there is no threshold set, then the return value is
   always <code>true</code>.
*/
public
boolean isAsSevereAsThreshold(Priority priority) {
  return ((threshold == null) || priority.isGreaterOrEqual(threshold));
}

跟到这里,看到这个threshold了,大概清楚问题是出在哪里了,既然上一步return了,说明这一步肯定是返回了false,这个threshold参数肯定是没有为null的,因为我在配置文件中写了INFO,那就只有后面的isGreaterOrEqual()方法了。

/**
   Returns <code>true</code> if this level has a higher or equal
   level than the level passed as argument, <code>false</code>
   otherwise.  
   
   <p>You should think twice before overriding the default
   implementation of <code>isGreaterOrEqual</code> method.
*/
public
boolean isGreaterOrEqual(Priority r) {
  return level >= r.level;
}

在该方法中,对两个日志级别进行了比较,一个是logger配置的level,一个是appender的threshold,如果传进来的logger超过了threshold的级别,那么不管你怎么配置,logger的日志最终都会以threshold的级别来输出,就类似于木桶效应,它打印的日志级别永远取决于Threshold的配置。

Priority.java

package org.apache.log4j;

/**
   <font color="#AA4444">Refrain from using this class directly, use
   the {@link Level} class instead</font>.

   @author Ceki G&uuml;lc&uuml; */
public class Priority {

  transient int level;
  transient String levelStr;
  transient int syslogEquivalent;

  public final static int OFF_INT = Integer.MAX_VALUE;
  public final static int FATAL_INT = 50000;
  public final static int ERROR_INT = 40000;
  public final static int WARN_INT  = 30000;
  public final static int INFO_INT  = 20000;
  public final static int DEBUG_INT = 10000;
  //public final static int FINE_INT = DEBUG_INT;
  public final static int ALL_INT = Integer.MIN_VALUE;

  // 多余代码省略掉...

}  

so,说到底还是自己配置错了~

再次感慨,在平时的工作中,真的是要温故知新呀!!!

log4j.rootLogger=INFO,console

# framework
log4j.logger.org.springframework=ERROR
log4j.logger.org.apache.ibatis=ERROR
log4j.logger.org.mybatis.spring=ERROR
log4j.logger.com.mchange.v2=ERROR

# self
log4j.logger.com.wolffy=DEBUG

# sql
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c - %m%n

修改配置如上所示,就可以正确打印出sql日志了,总之呢,就是最细粒度由Threshold控制,其他的自己根据不同的包名配置响应的日志级别。

log4j日志框架

看完文章,有任何疑问,请加入群聊一起交流!!!

很赞哦! ()

文章评论

  • 请先说点什么
    人参与,条评论

请使用电脑浏览器访问本页面,使用手机浏览器访问本页面会导致下载文件异常!!!

雨落无影

关注上方公众号,回复关键字【下载】获取下载码

用完即删,每次下载需重新获取下载码

若出现下载不了的情况,请及时联系站长进行解决

站点信息

  • 网站程序:spring + freemarker
  • 主题模板:《今夕何夕》
  • 文章统计:篇文章
  • 标签管理标签云
  • 微信公众号:扫描二维码,关注我们