使用log4j 2基本只需导入两个jar包:

log4j-core-xx.jar     log4j-api-xx.jar

 

log4j 2.0与以往的1.x有一个明显的不同,其配置文件只能采用.xml, .json或者 .jsn。在默认情况下,系统选择configuration文件的优先级如下:(classpath为scr文件夹)

1.classpath下名为 log4j-test.json 或者log4j-test.jsn文件

2.classpath下名为 log4j2-test.xml

3.classpath下名为 log4j.json 或者 log4j.jsn文件

4.classpath下名为 log4j2.xml



必须注意.xml 文件的文件名为log4j2



使用log4j 2.0,需要用LogManager的getLogger函数获取一个logger,就可以使用logger记录日志。



<?xml version="1.0" encoding="UTF-8"?>
<!-- status=debug 可以查看log4j的装配过程 -->
<Configuration status="off" monitorInterval="1800">

    <properties>
        <property name="LOG_HOME">logs/sample</property>
        <property name="FILE_NAME">mylog</property>
    </properties>

    <Appenders>
        <!-- 定义控制台输出 -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>

        <RollingRandomAccessFile name="running-log"
            fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/
                           $${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout
                pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - 
                           %msg%n" />
            <Policies>
                <!-- 每天生成一个日志文件 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 每到10M生成一个日志文件 -->
                <SizeBasedTriggeringPolicy size="10 MB" />
            </Policies>
            <!-- 最大保存文件数 -->
            <DefaultRolloverStrategy max="20" />
        </RollingRandomAccessFile>

        <!-- 文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,-->
        <!-- 这个也挺有用的,适合临时测试用 -->
        <File name="log" fileName="log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - 
                    %msg%xEx%n"/>
        </File>

        <!-- 这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入 -->
        <!-- 按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
        <RollingFile name="RollingFile" fileName="logs/app.log"
                     filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} 
                     %L %M - %msg%xEx%n"/>
            <SizeBasedTriggeringPolicy size="50MB"/>
        </RollingFile>

    </Appenders>
    
    <Loggers>
        <Logger name="com.cnblogs.yjmyzz.App2" level="trace"
            additivity="true">
            <AppenderRef ref="running-log" />
        </Logger>
        <Root level="error">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>


解释一下:


第3行中的 monitorInterval="1800"指log4j2每隔1800秒(半小时),自动监控该配置文件是否有变化,如果变化,则自动根据文件内容重新配置。



5-8行定义了一些属性(可以根据需要自己随便添加),主要是为了后面引用起来方便。

16行 RollingRandomAccessFile 即表示以文件方式记录,注意一下filePattern的设置,它与24行的SizeBasedTriggeringPolicy(表示单个文件最大多少容量)结合在一起,非常有用,以这段配置为例,当单个文件达到10M后,会自动将以前的内容,先创建类似 2014-09(年-月)的目录,然后按 "xxx-年-月-日-序号"命名,打成压缩包。

27行DefaultRolloverStrategy max="20"表示压缩包,最多保留20个。

45-48行,定义了一个新logger,它的级别是trace,使用文件方式来记录日志,additivity="true"这里注意一下,因为下面还有一个root logger,任何其它的logger最终都相当于继承自root logger,所以“com.cnblogs.yjmyzz.App2”这个logger中,如果记录了error及以上级别的日志,除了文件里会记录外,root logger也会生效,即:控制台也会输出一次。如果把additivity="true" 中的true,改成false,root logger就不会再起作用,即只会记录在文件里,控制台无输出。

TimeBasedTriggeringPolicy 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:

interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟

modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,那么假设上次封存日志的时间为03:00,则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00,16:00,。。。

 

 

loggers标签,用于定义logger的lever和所采用的appender,其中appender-ref必须为先前定义的appenders的名称,例如,此处为Console。那么log就会以appender所定义的输出格式来输出log。

root标签为log的默认输出形式,如果一个类的log没有在loggers中明确指定其输出lever与格式,那么就会采用root中定义的格式。

Appenders标签,其实就是输出,有各种扩展组件,主要类型有:

ConsoleAppender   输出结果到控制台

FileAppender  输出结果到指定文件

RollingFileAppender   同样输出结果到文件,区别是用一个buffer,因此速度会快点

 



这里介绍下RollingRandomessFile 的相关属性:



name:表示该appender的名称



fileName:表示输出的文件的路径



append:是否追加,true表示追加内容到所在的日志,false表示每次都覆盖



filePattern:表示当日志到达指定的大小或者时间,产生新日志时,旧日志的命名路径。



PatternLayout:和log4j1一样,指定输出日志的格式



Policies:策略,表示日志什么时候应该产生新日志,可以有时间策略和大小策略等



ThresholdFilter :过滤器, 如果你要选择控制台只能输出ERROR以上的类别,你就用ThresholdFilter,把level设置成ERROR,onMatch="ACCEPT" onMismatch="DENY" 的意思是匹配就接受,否则直接拒绝



另外关于logger的命名,很有讲究的,这里我们命名为com.cnblogs.yjmyzz.App2,如果正好有这样一个类:

package com.cnblogs.yjmyzz;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class App2 {

    static Logger logger = LogManager.getLogger();

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            logger.trace("trace message " + i);
            logger.debug("debug message " + i);
            logger.info("info message " + i);
            logger.warn("warn message " + i);
            logger.error("error message " + i);
            logger.fatal("fatal message " + i);
        }        
        System.out.println("Hello World! 2");
    }
}

log4j2是根据名称来用哪个logger的,第8行没有传任何参数,默认这个logger的name就是当前类的全称,即 com.cnblogs.yjmyzz.App2,这样就跟配置对应上了,所以刚才配置中的 nam="com.cnblogs.yjmyzz.App2"的logger,相当于只对App2这一个类起作用。

 

一个实用的配置文件

1)我正在调试某个类,所以,我不想让其他的类或者包的日志输出,否则会很多内容,所以,你可以修改上面root的级别为最高(或者谨慎起见就用ERROR),然后,加一个针对该类的logger配置,给appender-ref定义那个File appender,这个appender的好处是有一个append为false的属性,这样,每次运行都会清空上次的日志,这样就不会因为一直在调试而增加这个文件的内容,查起来也方便,这个和输出到控制台就一个效果了。

2)我已经基本上部署好程序了,然后我要长时间运行了。我需要记录下面几种日志,第一,控制台输出所有的error级别以上的信息。第二,我要有一个文件输出是所有的debug或者info以上的信息,类似做程序记录什么的。第三,我要单独为ERROR以上的信息输出到单独的文件,如果出了错,只查这个配置文件就好了,不会去处理太多的日志,怎么做呢?

>首先,在appenders下面加一个Console类型的appender,通过加一个ThresholdFilter设置level为error。(直接在配置文件的Console这个appender中修改)

>其次,增加一个File类型的appender(也可以是RollingFile或者其他文件输出类型),然后通过设置ThresholdFilter的level为error。

这里可以添加一个appender,内容如下:

 



<File name="ERROR" fileName="logs/error.log">
     <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
     <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>


并在loggers中的某个logger(如root)中引用(root节点加入这一行作为子节点)。 


<appender-ref ref="ERROR" />



 

>然后,增加一个RollingFile的appender,设置基本上同上面的那个配置文件。

>最后,在logger中进行相应的配置。不过如果你的logger中也有日志级别的配置,如果级别都在error以上,你的appender里面也就不会输出erro以下的信息了。

 

可能存在的问题:在Eclipse下一切运行正常,如果把应用打包成jar包发布后,cmd命令行模式下,即使Console开着的情况下,也没法输出,文件输出也没有任何日志。

问题解决方案:需要在MANIFEST.MF文件里Class-Path 最前加个'.',目的是让与jar包平级的配置文件log4j2.xml加载进来。

 

有时候,为了使同一份log4j文件要支持写到不同的log中,需要在载入的时候对内容进行动态修改,比如根据server id分别生成game1.log,game2.log

可以代码进行加载log4文件

 

File file = new File("log4j2.xml");  
BufferedInputStream in = null;  
try {  
    in = new BufferedInputStream(new FileInputStream(file));
    final ConfigurationSource source = new ConfigurationSource();  
    source.setInputStream(in);  
    Configurator.initialize(null, source);  
} catch (FileNotFoundException e) {  
    e.printStackTrace();  
}

 

官方建议一般程序员查看的日志改成异步方式,一些运营日志改成同步

 

 

Asynchronous Appenders 和 Asynchronous Loggers 区别:在</appenders> 节点里添加

 

<Async name="Async">
      <AppenderRef ref="MyFile"/>
</Async>


Asynchronous Appenders 性能比同步快,比Asynchronous Loggers慢

 

在loggers节点添加

 



<AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true">
      <AppenderRef ref="RandomAccessFile"/>
</AsyncLogger>


或者添加

 

 


<!-- Root Logger -->
<asyncRoot level="DEBUG">
<appender-ref ref="DevLog" />
<appender-ref ref="Console" />
</asyncRoot>

因为logger async 用的是无锁并发技术,必须引入Disruptor


 

测试下,单线程异步比同步效率提高了1倍。线程越多性能提高越明显。

如果要加上位置信息比如哪个类,第几行,需要设置 includeLocation="true" 但默认不设置好像也是true。

log4j2的按天分日志文件



<RollingFile name="error_appender" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error-%d{yyyy-MM-dd}.log">
    <PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss} [%thread] %m%n"/>
    <Policies>
    	<TimeBasedTriggeringPolicy modulate="true" interval="1"/>
    </Policies>
</RollingFile>



按大小分日志文件

 


<RollingFile name="error_appender" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error-%d{yyyy-MM-dd}-%i.log.gz">  
    <PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss} [%thread] %m%n"/>  
    <SizeBasedTriggeringPolicy size="100 MB" />  
</RollingFile>

按分钟分日志文件

 



<RollingRandomAccessFile name="_1min_appender" fileName="${MINUTE_HOME}/minute" filePattern="${MINUTE_HOME}/minute-%d{yyyy-MM-dd-HH-mm}.log">  
    <PatternLayout pattern="%m%n"/>  
    <Policies>  
        <TimeBasedTriggeringPolicy interval="1" modulate="true" />  
    </Policies>  
</RollingRandomAccessFile>



关键点在于 filePattern后的日期格式,以及TimeBasedTriggeringPolicy的interval,日期格式精确到哪一位,interval也精确到哪一个单位

log4j2 设置同一类型日志文件个数

 



<Appenders>  
    <Console name="Console" target="SYSTEM_OUT">  
         <PatternLayout pattern="[%-5p] %d %c - %m%n" />  
    </Console>  
    <File name="File" fileName="dist/my.log">  
         <PatternLayout pattern="%m%n" />  
    </File>  
    <RollingFile name="RollingFile" fileName="dist/my2.log"  
        filePattern="dist/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">  
        <PatternLayout pattern="[%-5p] %d %c - %m%n" />  
        <Policies>  
            <TimeBasedTriggeringPolicy />  
            <SizeBasedTriggeringPolicy size="25 KB" />  
        </Policies>  
        <DefaultRolloverStrategy max="20"/>  
    </RollingFile>  
</Appenders>



关键在于 <DefaultRolloverStrategy max="20"/>,如果不做配置,默认是7,这个7指的是上面i的最大值,超过了就会覆盖之前的