(一)主要是 log4j 中 myappender 过滤


之前曾写过一篇帖子,是log4j按包路径输出到不同文件。

log4j按级别输出到不同文件,也类似。

先看配置:




[html] ​​view plain​ ​ ​​copy​



  1. ### set log levels ###    
  2. log4j.rootLogger=info,error,info  
  3. log4j.appender.stdout=org.apache.log4j.ConsoleAppender     
  4. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout     
  5. log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n     
  6.       
  7. log4j.logger.info=info  
  8. log4j.appender.info=com.zznode.log.MyAppender    
  9. log4j.appender.info.layout=org.apache.log4j.PatternLayout     
  10. log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n  
  11. log4j.appender.info.datePattern='.'yyyy-MM-dd     
  12. log4j.appender.info.Threshold = INFO   
  13. log4j.appender.info.append=false   
  14. log4j.appender.info.File=D:/log4j/info.log   
  15.   
  16.   
  17. log4j.logger.error=error  
  18. log4j.appender.error=com.zznode.log.MyAppender     
  19. log4j.appender.error.layout=org.apache.log4j.PatternLayout     
  20. log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n   
  21. log4j.appender.error.datePattern='.'yyyy-MM-dd     
  22. log4j.appender.error.Threshold = ERROR     
  23. log4j.appender.error.append=false   
  24. log4j.appender.error.File=D:/log4j/error.log   


测试类:



[java] ​​view plain​ ​ ​​copy​



  1. import org.apache.log4j.PropertyConfigurator;  
  2. import org.apache.log4j.xml.DOMConfigurator;  
  3.   
  4. import com.zznode.test.Test;  
  5.   
  6. /** 
  7.  * @desc: 
  8.  * @since Nov 8, 2012 
  9.  * @author chaisson  
  10.  * 
  11.  * <p> 
  12.  */  
  13. public class Log4jApp {  
  14.       
  15.     public void printLog() {  
  16.         Logger log = Logger.getLogger(Log4jApp.class.getClass());  
  17.         log.info("测试info");  
  18.         log.debug("测试debug");  
  19.         log.error("测试error");  
  20.     }  
  21.       
  22.      public static void main(String[] args) {  
  23.   
  24.            //DOMConfigurator.configure("log4j.xml");  
  25.            PropertyConfigurator.configure("D:/workspace/Test/log4j-new.properties");    
  26.   
  27.            Log4jApp app = new Log4jApp();  
  28.            app.printLog();  
  29.              
  30.           // Test test = new Test();  
  31.           //test.printLog();  
  32.        }  
  33. }  


输出结果有点问题:info.log里面也包含了error的输出。

配置中关键的配置说明是这一句:

log4j.appender.debug.Threshold = INFO 

而它的作用是输出INFO级别以上的内容到info.log中,所以info.log文件中包含了ERROR级别的文件。


解决办法是:定义自己的Appender类,继承DailyRollingFileAppender,改写针对Threshold 的设置说明(重写针对级别的比较方法)

源代码




[java] ​​view plain​ ​ ​​copy​



  1. public boolean isAsSevereAsThreshold(Priority priority)  {    
  2.      return threshold == null || priority.isGreaterOrEqual(threshold);    
  3. }    

重写 isAsSevereAsThreshold(Priority priority)方法



[java] ​​view plain​ ​ ​​copy​



  1. /** 
  2.  * @desc: 
  3.  * @since Apr 17, 2013 
  4.  * @author chaisson  
  5.  * 
  6.  * <p> 
  7.  */  
  8. public class MyAppender extends DailyRollingFileAppender {  
  9.       
  10.     @Override  
  11.     public boolean isAsSevereAsThreshold(Priority priority) {    
  12.           //只判断是否相等,而不判断优先级     
  13.         return this.getThreshold().equals(priority);    
  14.     }    
  15. }  


这样,进行唯一判断,只有当Threshold与priority一致时,才进行输出,就实现了真正Log4j按照级别输出日志文件。

修改配置文件:



[plain] ​​view plain​ ​ ​​copy​



  1. ### set log levels ###    
  2. log4j.rootLogger=info,error,info  
  3. log4j.appender.stdout=org.apache.log4j.ConsoleAppender     
  4. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout     
  5. log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n     
  6.       
  7. log4j.logger.info=info  
  8. log4j.appender.info=com.zznode.log.MyAppender    
  9. log4j.appender.info.layout=org.apache.log4j.PatternLayout     
  10. log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n  
  11. log4j.appender.info.datePattern='.'yyyy-MM-dd     
  12. log4j.appender.info.Threshold = INFO   
  13. log4j.appender.info.append=false   
  14. log4j.appender.info.File=D:/log4j/info.log   
  15.   
  16.   
  17. log4j.logger.error=error  
  18. log4j.appender.error=com.zznode.log.MyAppender     
  19. log4j.appender.error.layout=org.apache.log4j.PatternLayout     
  20. log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n   
  21. log4j.appender.error.datePattern='.'yyyy-MM-dd     
  22. log4j.appender.error.Threshold = ERROR     
  23. log4j.appender.error.append=false   
  24. log4j.appender.error.File=D:/log4j/error.log   


这样才算完成了。


补充:有同事讨论,如果是XML配置,通过filter会简便:




[html] ​​view plain​ ​ ​​copy​



  1. <filter class="org.apache.log4j.varia.LevelRangeFilter">  
  2. <param name="LevelMin" value="ERROR"/>  
  3. <param name="LevelMax" value="ERROR"/>  
  4. </filter>  


有兴趣的朋友,可以自己动手尝试下。







(二)主要是log4j 中  properties 中建立子logger;properties 与 xml 的类比,尤其分包输出





1、Logger 完成日志信息的处理

 定义输出的层次和决定信息是否输出

 DEBUG < INFO < WARN < ERROR

2、Appender 设置日志信息的去向

常用的:

org.apache.log4j.ConsoleAppender(控制台)

org.apache.log4j.FileAppender(文件)

org.apache.log4j.DailyRollingFileAppener(每天产生一个日志文件)

org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)

org.apache.log4j.WriterAppender(将日志讯息以串流格式发送到任意指定的地方)

org.apache.log4j.JdbcAppender(将日志讯息保存到​​数据库​​中)

3、Layout 设置日志信息的输出样式

layout有以下几种:

org.apache.log4j.HTMLLayout(以HTML表格形式布局)

org.apache.log4j.SimpleLayout(包含日志讯息的级别和讯息字符串)

org.apache.log4j.TTCCLayout(包含日志产生的时间、执行绪、类别等讯息)

org.apache.log4j.PatterLayout(可以灵活地指定布局格式)

4、配置文件 log4j.properties或log4j.xml


log4j.properties实例:





[plain] ​​view plain​ ​ ​​copy​



  1. log4j.logger.com.jjm.util=INFO, A1,A2  
  2. log4j.logger.com.jjm.dao=DEBUG, A1                     (com.jjm.util和com.jjm.dao是class全名匹配字符串)      
  3.   
  4. log4j.appender.A1=org.apache.log4j.ConsoleAppender  
  5. log4j.appender.A1.layout=org.apache.log4j.PatternLayout  
  6. log4j.appender.A1.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n  
  7.   
  8. log4j.appender.A2=org.apache.log4j.RollingFileAppender  
  9. log4j.appender.A2.File=sshdemo.log  
  10. log4j.appender.A2.MaxFileSize=500KB  
  11. log4j.appender.A2.MaxBackupIndex=1  
  12. log4j.appender.A2.layout=org.apache.log4j.PatternLayout  
  13. log4j.appender.A2.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n  






log4j.xml实例:





[html] ​​view plain​ ​ ​​copy​



  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  
  3. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">  
  4. <appender name="A1" class="org.apache.log4j.RollingFileAppender">  
  5.     <param name="File" value="sshdemo2.log" />  
  6.     <param name="MaxFileSize" value="1MB" />  
  7.     <param name="MaxBackupIndex" value="10" />  
  8.     <layout class="org.apache.log4j.PatternLayout">  
  9.         <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n" />  
  10.     </layout>  
  11. </appender>  
  12.   
  13. <appender name="A2" class="org.apache.log4j.ConsoleAppender">  
  14.     <layout class="org.apache.log4j.PatternLayout">  
  15.         <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n" />  
  16.     </layout>  
  17. </appender>  
  18.   
  19. <logger name="com.jjm.dao">  
  20.     <level value="DEBUG" />  
  21.     <appender-ref ref="A1" />  
  22. </logger>  
  23.   
  24. <root>  
  25.     <priority value="DEBUG" />  
  26.     <appender-ref ref="A2" />  
  27. </root>  
  28.   
  29. </log4j:configuration>  




格式说明layout中的参数都以%开始,后面不同的参数代表不同的格式化信息(参数按字母表顺序列出):

%c        输出所属类的全名,可在修改为 %d{Num} ,Num类名输出的维(如:"org.apache.elathen.ClassName",%C{2}将输出elathen.ClassName)

%d       输出日志时间其格式为 %d{yyyy-MM-dd HH:mm:ss,SSS},可指定格式 如 %d{HH:mm:ss}

%l        输出日志事件发生位置,包括类目名、发生线程,在代码中的行数

%n       换行符

%m      输出代码指定信息,如info(“message”),输出message

%p       输出优先级,即 FATAL ,ERROR 等

%r        输出从启动到显示该log信息所耗费的毫秒数

%t        输出产生该日志事件的线程名

(三)主要是logback中的filter

最近才开始在项目中使用logback,有一种相见恨晚的感觉,因为它很轻易的满足了我的几个需求:


        1. 配置简单,易于上手

        2. 一个日志文件中只能某一个级别的日志

        3. 一个类中可以指定多个不同的日志,并且生成的每个日志文件中只包含其本身的内容

        4. 可以关闭或者打开某几个包的日志,并且可以设置不同的包使用不同的日志级别。

       一、易用性

        logback的易用性不用多讲,只需要通过下面两行就可以在console中输出日志:





[java] ​​view plain​ ​ ​​copy​


 ​​print​​​​?​

  1. <pre name="code" class="html">Logger debugLogger = LoggerFactory.getLogger(MyClass.class);  
  2. </pre>logger.info("This is a log");  


      程序运行时,logback会查找默认的配置文件logback.xml或者logback-test.xml文件,如果没有找到它就会使用默认的配置,将日志打印到console中。下面是一个简单配置文件(​​http://logback.qos.ch/manual/configuration.html​​):






[html] ​​view plain​ ​ ​​copy​


 ​​print​​​​?​

  1. <configuration>  
  2.   
  3.   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
  4.     <!-- encoders are assigned the type  
  5.          ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->  
  6.     <encoder>  
  7.       <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>  
  8.     </encoder>  
  9.   </appender>  
  10.   
  11.   <root level="debug">  
  12.     <appender-ref ref="STDOUT" />  
  13.   </root>  
  14. </configuration>  


       二、日志级别限制


       在多数的Log工具中,级别是可以传递,例如如果指定了日志输出级别为DEBUG,那么INFO、ERROR级别的log也会出现在日志文件。这种默认给程序的调试带来了很多的麻烦。而在logback中可以通过appender中的filter来严格限制日志的输出级别:





[html] ​​view plain​ ​ ​​copy​


 ​​print​​​​?​

  1. <filter class="ch.qos.logback.classic.filter.LevelFilter">  
  2.     <level>INFO</level>  
  3.     <onMatch>ACCEPT</onMatch>  
  4.     <onMismatch>DENY</onMismatch>  
  5. </filter>  

上面的设置中只会在文件中出现级别为INFO的日志内容。


     三、同一个类中包含不同的日志

     有时候一个类中可能要求打印不同的日志信息,例如有的用来调试,有的用来记录程序运行中的某些参数的变化等等。这时候可以通过下面的语句声明不同的日志:





[java] ​​view plain​ ​ ​​copy​


 ​​print​​​​?​

  1. Logger debugLogger = LoggerFactory.getLogger(MyClass.class);  
  2. Logger monitorLogger = LoggerFactory.getLogger("monitor");  

    然后在配置文件中分别指定不同的输出文件(debugLogger使用默认的配置):






[html] ​​view plain​ ​ ​​copy​


 ​​print​​​​?​

  1.     <appender name="monitor" class="ch.qos.logback.core.rolling.RollingFileAppender">  
  2.         <File>${log.dir}/monitor.log</File>  
  3.         <encoder>  
  4.             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} : %m%n</pattern>  
  5.         </encoder>  
  6.         <filter class="ch.qos.logback.classic.filter.ThresholdFilter">  
  7.             <level>INFO</level>  
  8.         </filter>  
  9.         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
  10.             <fileNamePattern>${log.dir}/sensitive.log.%d{yyyy-MM-dd}</fileNamePattern>  
  11.         </rollingPolicy>  
  12.     </appender>  
  13.         <logger name="monitor" additivity="false" level="INFO">  
  14. <span style="white-space:pre">      </span><appender-ref ref="monitor" />  
  15. <span style="white-space:pre">  </span></logger>  

 这里通过设置additivity="false"禁止monitor里的内容向上传递,否则会同时显示在默认的日志中。


         四、精确控制日志的应用范围

         在程序调试中,经常出现的情况是:错误只在某一个或者几个类或者包里,所以只需要打开这几个类或者包里的DEBUG级别的log。在以前的项目,使用​​spring​​和​​hibernate​​时,一旦打开DEBUG级别的log,程序本身的debug信息就会被Spring和Hibernate的大量日志淹没,大大降低了调试的效率。而logback让这一切变的简单起来了:





[html] ​​view plain​ ​ ​​copy​


 ​​print​​​​?​

  1. <logger name="org" level="ERROR" />  

这一行就将org包下面的所有日志级别设为了ERROR,不会再打扰我们的DEBUG。