log4j框架logger的继承关系以及使用场景

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了log4j框架logger的继承关系以及使用场景相关的知识,希望对你有一定的参考价值。

log4j框架logger的继承关系以及使用场景

log4j日志框架logger是存在继承关系的,我们一般都会在log4j.properties文件中定义log4j.rootLogger。其他所有logger都继承自这个rootLooger。考虑下面这种场景:假如我们有2个类HelloLog4j和A。

[java] 
  1. package aty.log;  
  2.   
  3. import org.apache.log4j.Logger;  
  4.   
  5. import aty.log.service.A;  
  6.   
  7. public class HelloLog4j {  
  8.   
  9.     private static Logger logger = Logger.getLogger(HelloLog4j.class);  
  10.   
  11.     public static void main(String[] args) {  
  12.         logger.debug("log in main.");  
  13.         new A().run();  
  14.     }  
  15. }  
[java] 
 
  1. package aty.log.service;  
  2.   
  3. import org.apache.log4j.Logger;  
  4.   
  5. public class A {  
  6.   
  7.     private static Logger logger = Logger.getLogger(A.class);  
  8.   
  9.     public void run() {  
  10.         logger.error("log in A.java");  
  11.     }  
  12. }  

 

log4j.properties文件配置如下:
[plain] 
 
  1. #rootLogger can print DEBUG to console  
  2. log4j.rootLogger=debug, console  
  3. log4j.appender.console=org.apache.log4j.ConsoleAppender    
  4. log4j.appender.console.Threshold=debug    
  5. log4j.appender.console.ImmediateFlush=true    
  6. log4j.appender.console.Target=System.err    
  7. log4j.appender.console.layout=org.apache.log4j.PatternLayout  

 

运行HelloLog4j.java控制台日志如下:可以看到这2个类使用的logger都是rootLogger。

技术分享图片

现在我们有这个需求:让A.java中日志的打印到单独的a.log日志文件中,而HelloLog4j中的日志还是打印到控制台。也就是说:我们想让A和HelloLog4j这2个类使用不同的logger。java代码不用修改,我们将log4j.properties修改如下:

[java] 
 
  1. #rootLogger can print DEBUG to console  
  2. log4j.rootLogger=debug, console  
  3. log4j.appender.console=org.apache.log4j.ConsoleAppender    
  4. log4j.appender.console.Threshold=debug    
  5. log4j.appender.console.ImmediateFlush=true    
  6. log4j.appender.console.Target=System.err    
  7. log4j.appender.console.layout=org.apache.log4j.PatternLayout  
  8. log4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%t]-[%X{ip}]-[%l]-[%p] %m%n  
  9.   
  10. #A.java is special.we use a individual appender for it.  
  11. #A class‘s full qulified qualified name is logger‘s name.  
  12. log4j.logger.aty.log.service.A=DEBUG, testA  
  13. log4j.appender.testA=org.apache.log4j.FileAppender  
  14. log4j.appender.testA.Threshold=warn    
  15. log4j.appender.testA.ImmediateFlush=true    
  16. log4j.appender.testA.Append=true    
  17. log4j.appender.testA.File=c:/a.log  
  18. log4j.appender.testA.layout=org.apache.log4j.PatternLayout  
  19. log4j.appender.testA.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%t]-[%X{ip}]-[%l]-[%p] %m%n  
  20.   
  21. #avoid print to parent logger.  
  22. log4j.additivity.aty.log.service.A= false  

 

再次运行HelloLog4j可以看到:A.java中的日志并没有打印到控制台上,而是打印到了a.log文件中。

技术分享图片

我们来解释下上面的配置:

log4j.logger.aty.log.service.A=DEBUG, testA    我们用A的全类名定义了一个logger。

log4j.additivity.aty.log.service.A= false     避免日志打印到rootLogger中。如果这里设置成true,那么A.java中的日志既会打印到控制台上,也会打印到a.log文件中。

 

现在我们可以介绍下logger的继承关系了,比如我们上面的类aty.log.service.A中使用了logger来写日志。那么log4j会先查找名称是"aty.log.service.A"的logger,如果没有找到,向上查找名称是"aty.log.service"的logger,如果还没有找到那么继续向上查找,查找的最顶层就是rootLogger。这就是log4j中logger的继承关系。rootLogger一定要在配置,其他特定类或者特定包的logger可以不用配置。知道了这个继承特性之后,如果我们要aty.log.dao包下所有的类都打印到同一个日志文件,那么可以进行如下配置。

[plain] 
 
  1. # a package appender  
  2. log4j.logger.aty.log.dao=DEBUG, daoAppender  
  3. log4j.appender.daoAppender=org.apache.log4j.FileAppender  
  4. log4j.appender.daoAppender.Threshold=warn    
  5. log4j.appender.daoAppender.ImmediateFlush=true    
  6. log4j.appender.daoAppender.Append=true    
  7. log4j.appender.daoAppender.File=c:/dao.log  
  8. log4j.appender.daoAppender.layout=org.apache.log4j.PatternLayout  
  9. log4j.appender.daoAppender.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%t]-[%X{ip}]-[%l]-[%p] %m%n  
  10. log4j.additivity.aty.log.dao= false  

 

 

可以看到:利用logger的继承特性,我们可以很容易将不同的日志打印到不同的文件中,这样可以避免各种日志混杂在一起。如果我们想将A.java中有的日志打印到a.log中,有的日志打印到控制台上也是可以的。
[java] 
 
  1. package aty.log.service;  
  2.   
  3. import org.apache.log4j.Logger;  
  4.   
  5. public class A {  
  6.   
  7.     private static Logger logger = Logger.getLogger(A.class);  
  8.       
  9.     private static Logger rootLogger = Logger.getRootLogger();  
  10.   
  11.     public void run() {  
  12.         logger.error("log in A.java");  
  13.         rootLogger.error("a to console.");  
  14.     }  
  15. }  
技术分享图片


 

最后提一下:log4j默认是使用类名或者包名来查找logger的。log4j允许我们自己定义logger的名称。

[java]
 
  1. package aty.log.service;  
  2.   
  3. import org.apache.log4j.Logger;  
  4.   
  5. public class A {  
  6.   
  7.     private static Logger logger = Logger.getLogger("atyAlogger");  
  8.       
  9.     public void run() {  
  10.         logger.error("log in A.java");  
  11.     }  
  12. }  
[plain] 
 
  1. #use atyAlogger as appender name.  
  2. log4j.logger.atyAlogger=DEBUG, testA  
  3. log4j.appender.testA=org.apache.log4j.FileAppender  
  4. log4j.appender.testA.Threshold=warn    
  5. log4j.appender.testA.ImmediateFlush=true    
  6. log4j.appender.testA.Append=true    
  7. log4j.appender.testA.File=c:/a.log  
  8. log4j.appender.testA.layout=org.apache.log4j.PatternLayout  
  9. log4j.appender.testA.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%t]-[%X{ip}]-[%l]-[%p] %m%n  
  10.   
  11. #avoid print to parent logger.  
  12. log4j.additivity.atyAlogger= false  

一般来说,我们都是使用默认的名称,这样虽然将类名和包名在log4j.properties写死了。但是方便java类里面获取logger。因为各个类都是根据自己类的全限定名来查找logger的,具体日志到底打印到哪里去,由配置文件决定。

 

 













以上是关于log4j框架logger的继承关系以及使用场景的主要内容,如果未能解决你的问题,请参考以下文章

log4j2源码分析

日志框架Log4j源码解析

log4j配置文件中的additivity属性

python logging继承关系

log4j日志框架的使用

log4j