Log4j

 


Log4j

通过配置文件(log4j.xml或log4j.properties)控制日志的输出,包括输出格式、输出形式、输出级别等,主要组件是apache的log4jjar包和配置文件;
一、组件:log4j jar包和配置文件

二、应用步骤

(1)在classpath下添加配置文件

(2)class内引入   import org.apache.log4j.Logger
(3)声明一个logger private static Logger logger = Logger.getLogger(ClassName.class); 
(4)在程序中的相应位置加入输出信息:logger.info("用户登录:"+user.getAccount());

三、配置文件说明

1、 log4j.rootCategory=INFO, stdout , R
此句为将等级为INFO的日志信息输出到stdout和R这两个目的地,stdout和R的定义在下面的代码,可以任意起名。
等级可分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL,如果配置OFF则不打出任何信息,如果配置为INFO这样只显示INFO, WARN, ERROR的log信息,而DEBUG信息不会被显示,优先级:ALL < DEBUG < INFO <WARN < ERROR < FATAL < OFF2、 log4j.appender.stdout=org.apache.log4j.ConsoleApp此句为定义名为stdout的输出端是哪种类型,可以是

org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

3、 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
此句为定义名为stdout的输出端的layout是哪种类型,可以是
org.apache.log4j.HTMLLayout(以HTML表格形式布局,
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串,
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息

4、 log4j.appender.stdout.layout.ConversionPattern= [QC] %p [%t] %C.%M(%L) | %m%n
如果使用pattern布局就要指定的打印信息的具体格式ConversionPattern,打印参数如下:
%m 输出代码中指定的消息;
%M 输出打印该条日志的方法名;
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL;
%r 输出自应用启动到输出该log信息耗费的毫秒数;
%c 输出所属的类目,通常就是所在类的全名;
%t 输出产生该日志事件的线程名;
%n 输出一个回车换行符,Windows平台为"rn”,Unix平台为"n”;
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy-MM-dd HH:mm:ss,SSS},输出类似:2002-10-18 22:10:28,921;
%l 输出日志事件的发生位置,及在代码中的行数;
[QC]是log信息的开头,可以为任意字符,一般为项目简称。
输出的信息:[TS] DEBUG [main] AbstractBeanFactory.getBean(189) | Returning cached instance of singleton bean 'MyAutoProxy'

6、 log4j.appender.R=org.apache.log4j.DailyRollingFileAppender 此句与第3行一样。定义名为R的输出端的类型为每天产生一个日志文件。

7、 log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log  此句为定义名为R的输出端的文件名和路径为D:\Tomcat 5.5\logs\qc.log可以自行修改。

以下是设置框架包中日志级别   这些包的设置可根据项目的实际情况而自行定制。
8、 log4j.logger.com. neusoft =DEBUG 指定com.neusoft包下的所有类的等级为DEBUG。

9、 log4j.logger.com.opensymphony.oscache=ERROR

10、log4j.logger.net.sf.navigator=ERROR 这两句是把这两个包下出现的错误的等级设为ERROR,如果项目中没有配置EHCache,则不需要这两句。
11、 log4j.logger.org.apache.commons=ERROR
12、 log4j.logger.org.apache.struts=WARN  这两句是struts的包。
13、log4j.logger.org.displaytag=ERROR  这句是displaytag的包。(QC问题列表页面所用)
14、 log4j.logger.org.springframework=DEBUG    此句为Spring的包。
15、log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
16、log4j.logger.org.hibernate=DEBUG   此两句是hibernate的包。

四、配置文件解
Log4j支持两种配置文件格式,一种是XML(标准通用标记语言下的一个应用)格式的文件,一种是Java特性文件log4j.properties(键=值)。

下面将介绍使用log4j.properties文件作为配置文件的方法:
①、配置根Logger    Logger 负责处理日志记录的大部分操作。
其语法为: log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的总开关。比如在这里定义了INFO级别,只有等于及高于这个级别的才进行处理,则应用程序中所有DEBUG级别的日志信息将不被打印出来。ALL:打印所有的日志,OFF:关闭所有的日志输出。 appenderName就是指定日志信息输出到哪个地方。可同时指定多个输出目的地。
②、配置日志信息输出目的地 Appender
Appender 负责控制日志记录操作的输出。
其语法为:
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1

log4j.appender.appenderName.optionN = valueN
这里的appenderName为在①里定义的,可任意起名。
其中,Log4j提供的appender有以下几种:
org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),可通过log4j.appender.R.MaxFileSize=100KB设置文件大小,还可通过log4j.appender.R.MaxBackupIndex=1设置为保存一个备份文件。
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
例如:log4j.appender.stdout=org.apache.log4j.ConsoleAppender
定义一个名为stdout的输出目的地,ConsoleAppender为控制台。
③、配置日志信息的格式布局Layout    Layout 负责格式化Appender的输出。
其语法为:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1

log4j.appender.appenderName.layout.optionN = valueN
其中,Log4j提供的layout有以下几种:
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
格式化日志信息
Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:
%m 输出代码中指定的消息;
%M 输出打印该条日志的方法名;
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL;
%r 输出自应用启动到输出该log信息耗费的毫秒数;
%c 输出所属的类目,通常就是所在类的全名;
%t 输出产生该日志事件的线程名;
%n 输出一个回车换行符,Windows平台为"rn”,Unix平台为"n”;
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy-MM-dd HH:mm:ss,SSS},输出类似:2002-10-18 22:10:28,921;
%l 输出日志事件的发生位置,及在代码中的行数。

另:log4j.appender.FILE.Threshold Threshold是个全局的过滤器,它将把低于所设置的level的信息过滤不显示出来。

五、log4j.properties与log4j.xml

log4j.properties配置文件,配置简单,但不支持复杂过滤器filter,log4j.xml虽然配置文件看似复杂,但支持复杂过滤器和Log4j的新特性。推荐使用log4j.xml

1、路径问题:d:/log/abc.log   可以指定但分隔符是斜线   不是windows特有的反斜线
2、如果在程序中使用log.setLevel(Level.DEBUG);设置了日志级别  会覆盖配置文件中配置的日志级别

附上log4j.xml示例:

<?xml version="1.0" encoding="UTF-8"?>     
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">     
        
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' >     
        
    <appender name="myConsole" class="org.apache.log4j.ConsoleAppender">     
        <layout class="org.apache.log4j.PatternLayout">     
            <param name="ConversionPattern"        
                value="[%d{dd HH:mm:ss,SSS} %-5p] [%t] %c{2} - %m%n" />     
        </layout>     
        <!--过滤器设置输出的级别-->     
        <filter class="org.apache.log4j.varia.LevelRangeFilter">     
            <param name="levelMin" value="debug" />     
            <param name="levelMax" value="warn" />     
            <param name="AcceptOnMatch" value="true" />     
        </filter>     
    </appender>     
     
    <appender name="myFile" class="org.apache.log4j.RollingFileAppender">        
        <param name="File" value="D:/output.log" /><!-- 设置日志输出文件名 -->     
        <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->     
        <param name="Append" value="true" />     
        <param name="MaxBackupIndex" value="10" />     
        <layout class="org.apache.log4j.PatternLayout">     
            <param name="ConversionPattern" value="%p (%c:%L)- %m%n" />     
        </layout>     
    </appender>     
       
    <appender name="activexAppender" class="org.apache.log4j.DailyRollingFileAppender">     
        <param name="File" value="E:/activex.log" />       
        <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />       
        <layout class="org.apache.log4j.PatternLayout">     
         <param name="ConversionPattern"       
            value="[%d{MMdd HH:mm:ss SSS} %-5p] [%t] %c{3} - %m%n" />     
        </layout>       
    </appender>     
        
    <!-- 指定logger的设置,additivity指示是否遵循缺省的继承机制-->     
    <logger name="com.runway.bssp.activeXdemo" additivity="false">     
        <priority value ="info"/>       
        <appender-ref ref="activexAppender" />       
    </logger>     
     
    <!-- 根logger的设置-->     
    <root>     
        <priority value ="debug"/>     
        <appender-ref ref="myConsole"/>     
        <appender-ref ref="myFile"/>        
    </root>     
</log4j:configuration>

六、Log4j启动过程

除了Log4j之外,还需要一个common-logging来协同进行日志记录。common-logging是一个日志的管理框架,具体的事情还是交由log4j来进行记录。

源码:
Logger getLogger(Class clazz)

 {   
       return LogManager.getLogger(clazz.getName());   
 }  

转入LogManager,首先应该注意的是这个类的static块, 这个块其实就是一个加载log4j配置文件的过程。即在程序启动之初,在JVM需要加载这个类时,这个初始化块会自动运行,并且加载整个配置,以完成log4j的启动。
Java代码  
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));   
......   
OptionConverter.selectAndConfigure(url, configuratorClassName,  LogManager.getLoggerRepository());  

上面的所有代码均完成两件事,第一件事就是构造一个ROOT的Logger对象,此对象作为所有logger对象的最上层,其它logger的相应属性均从这个对象进行继承或改写,就好像java里的继承一样,这个类是内定的,不能由配置文件直接指定,且root都是在最顶层的,其他logger均在此下,这样形成一个完整的logger树。下层可以引用上层,上层管理下层。    第二件事则是去寻找配置文件的地址信息,通过各种方法都寻找log4j.xml或log4j.properties文件,然后对文件进行解析。(在此处,通过properties文件进行解析)
Java代码  
OptionConverter.void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy)  
这个方法会最终通过指定的文件解析类(此处是PropertyConfigurator)进行解析,转入。

Java代码  
configurator.doConfigure(url, hierarchy)  
这个方法将,url转化成一个properties对象,进行解析。
Java代码  
doConfigure(props, hierarchy); 进入这个方法
Java代码  
String value = properties.getProperty(LogLog.DEBUG_KEY);//即log4j.debug   
if(value == null)    
value = properties.getProperty("log4j.configDebug");   
if(value != null)    
LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));

  上面方法读取一个关于log4j自身的debug Level信息,主要用于log4j内部在解析时调用(因为log4j还不能使用logger对象进行写信息,它用到一个LogLog的类,来模拟logger记录,用于在自身解析的过程中输出一些信息),一般来说,这个都用不到。

主要的信息集中在以下三句话:
Java代码  
configureRootCategory(properties, hierarchy);   
configureLoggerFactory(properties);   
parseCatsAndRenderers(properties, hierarchy);  
configureRootCategory(properties, hierarchy);
configureLoggerFactory(properties);
parseCatsAndRenderers(properties, hierarchy);
 
第一句话用于解析root根对象上的相关配置。
第二句话用于解析loggerFactory(factory用于创建logger对象)
第三句话用于解析除rootLogger之外的其他logger以及render信息。
当然上面这个方法,即不是尽为rootLogger服务,对于其他logger也调用这个方法,故上面在解析Level时,对root作了单独判断(因为rootLogger的Level不能为空,至少均需要一个值)。处理Level,即将level值简单设置在logger上即可以了。
   接下来即解析appender信息,通过紧接着level后面的字符串,按列表方式进行解析,然后将appender加入logger的appenderList(即要进行信息处理的监听器表)中。进入parseAddpender(解析appender)即是解析appender对象,通过log4j.appender.X的前缀(X表示在rootLogger后的appender名称)来取得appender类名,并尝试实例化,然后根据appender来判断是否需要再解析appender的layout(即log4j.appender.X.layout这个键),解析并设置相应属性,最后分别解析appender本身的属性信息和layout的属性信息。(通过ProperSetter这个类,根据javaBean属性映射,将指定后缀后的信息当作一个键,后缀在属性文件中的值作为指定键的值,并将这个键值映射,通过javaBean设置到相应的对象上)至此,rootLogger即解析完毕。
第二句:解析loggerFactory,略。
第三句:解析其他logger信息。 
至此,整个log4j的配置信息已经完成,而这个配置是由JVM保证线程化的(即只能被加载一次),在使用时整个配置已经加载成功,得到的已经是从配置信息中得到的logger对象了。


七、Log4j加载配置文件位置的顺序:
默认情况下,log4j 会自动加载classpath 中的配置文件。而且没有打包的log4j.properties 优先于大在jar 包中的log4j.properties 文件。

加载顺序: 
1  Trying to find [" + resource + "] using context classloader " + classLoader + "."       加载本工程中的配置文件
2  Trying to find [" + resource + "] using " + classLoader + " class loader.          加载jar 包中的配置文件
3   Trying to find [" + resource + "] using ClassLoader.getSystemResource().  加载系统类路径的配置文件

八、日志级别三层过滤:根记录器,子记录器,Appender的Threshold配置级别

所有包中都会使用logger.debug(),logger.info(),logger.warn(),logger.error()来设置不同级别的日志记录,那么什么样的日志才会被打印出来呢?

按照日志记录过滤的顺序来看:根据记录器配置的级别,大于这个级别的将被记录,小于的过滤掉以后也不会被记录;

主记录器设定的级别,如果对同一包配置子记录器,不管级别高低,子记录器级别会覆盖根记录器级别;

然后Appender的Threshold配置级别,如果级别高于记录器级别 则按此级别输出,否则按记录器级别输出;

原文地址:https://www.cnblogs.com/cac2020/p/5225173.html