您现在的位置是:网站首页 > 代码编程 > JAVA开发JAVA开发
【原】为什么说在log4j中Threshold拥有最高优先级
             不忘初心
            2020-09-18
            围观()
            评论()
            点赞()
            【JAVA开发】
            不忘初心
            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

在它里面有一个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ülcü */
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控制,其他的自己根据不同的包名配置响应的日志级别。
看完文章,有任何疑问,请加入群聊一起交流!!!
很赞哦! ()
相关文章
标签云
猜你喜欢
- IntelliJ IDEA 2019.2已经可以利用补丁永久破解激活了
- IntelliJ IDEA 2019.3利用补丁永久破解激活教程
- IntelliJ IDEA高版本最灵活的永久破解激活方法(含插件激活,时长你说了算)
- Jetbrains全家桶基于ja-netfilter的最新破解激活详细图文教程
- IntelliJ IDEA 2022.1永久破解激活教程(亲测可用,持续更新)
- 分享几个正版 IntelliJ IDEA 激活码(破解码、注册码),亲测可用,持续更新
- ja-netfilter到底需不需要mymap,2021.3.2版本激活失效?
- 如何激活idea2022.1及以上版本中的插件(亲测可用)
- 【史上最全】IntelliJ IDEA最新2022.1版本安装和激活视频教学(含插件)
- IntelliJ IDEA 2022.2 版本最新2099年永久激活方法,亲测可用,也可以开启新UI了。
站点信息
- 网站程序:spring + freemarker
- 主题模板:《今夕何夕》
- 文章统计:篇文章
- 标签管理:标签云
- 微信公众号:扫描二维码,关注我们
 























