log4j2的使用



1、从HelloWorld开始

参考:http://logging.apache.org/log4j/2.x/manual/api.html

首先创建一个Java Project,如下图,在项目中创建lib文件夹,将log4japicore包复制进去并配置到项目编译路径中。

创建包com.demo并在包内创建类HelloWorld


HelloWorld类的内容如下:

package com.demo;

 

import org.apache.logging.log4j.LogManager;

import org.apache.logging.log4j.Logger;

 

public class HelloWorld {

    private static final Logger logger = LogManager.getLogger("HelloWorld");

    public static void main(String[] args) {    

     String hello = "Hello, World!";    

        logger.trace("TRACE: " + hello);

        logger.debug("DEBUG: " + hello);

        logger.info("INFO: " + hello);

        logger.warn("WARN: " + hello);

        logger.error("ERROR: " + hello);

        logger.fatal("FATAL: " + hello);

    }

}

运行HelloWorld,结果显示如下:

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

00:06:16.530 [main] ERROR HelloWorld - ERROR: Hello, World!

00:06:16.532 [main] FATAL HelloWorld - FATAL: Hello, World!

 

运行时提示没有找到Log4j2的配置文件,使用默认配置,只显示error到控制台。

缺省的配置等同于如下配置,其中Root指定的level是error,所有只输出了error和fatal级别的日志。

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="WARN">  //status

<Appenders>   定义输出位置

<Console name="Console" target="SYSTEM_OUT">  //target输出位置

<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>  //格式

</Console>

</Appenders>

<Loggers>   //定义一个Loggers

<Root level="error">

<AppenderRef ref="Console"/>   //根据上面的Console

</Root>

</Loggers>

</Configuration>

 

2、理解log4j2的结构

参考:http://logging.apache.org/log4j/2.x/manual/architecture.html

结合我们的HelloWorld程序,我们看一下log4j2的结构:

LoggerContext是整个Log系统的锚点,每一个LoggerContext会含有一个Configuration,在congfiguration中会包含Appender(输出器)、Filter(过滤器)、LoggerConfigStrSubstitutor的引用。

当我们在配置文件中声明一个Loggers时就会创建一个LoggerConfig, LoggerConfig包含有一组Filter,同时持有一组Appender的引用。LoggerConfig所收到的所有LogEvent首先经过过滤器处理才会传递给Appendar输出。

Filter会存在三种返回结果:AcceptDenyNeutralAccept表示事件将直接被处理并不继续转发其他FilterDeny表示事件将被忽略,Neutral表示事件将被转发给下一个filter,如果没有后续的filter,事件将被处理。


3、理解Named Hierarchy (日志名称层次规则)

首先我们在com.demo包内新增一个类NamedHierarchy:

package com.demo;

 

import org.apache.logging.log4j.LogManager;

import org.apache.logging.log4j.Logger;

 

public class NamedHierarchy {

 private static final Logger logger = LogManager.getLogger(NamedHierarchy.class);   //注意,这里是class,不是String字符串。可以按层次结构定位

public static void main(String[] args) {

// TODO Auto-generated method stub

String nh = "Named Hierarchy";    

logger.getLevel();

        logger.trace("TRACE: " + nh + " " + logger.getLevel());       

        NamedHierarchy n = new NamedHierarchy();

        n.run();

        logger.error("ERROR: " + nh + " " + logger.getLevel());

        

}

 

public void run(){

String nh = "NamedHierarchy.run";    

     logger.debug("DEBUG: " + nh + " " + logger.getLevel());     

}

}

 

src下新增log4j2.xml,并按如下修改文件:

<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="WARN">

  <Appenders>   //定义一个输出器

 

                                //Appenders always have a name so that they can be referenced from Loggers.

    <Console name="Console" target="SYSTEM_OUT">     //控制台

      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

    </Console>

  </Appenders>


  <Loggers>      //包含有一组Filter(logger,根据name过滤),同时持有一组Appender的引用,里面有很多logger,每个logger含有appenders的引用

     <Logger name="com.demo.NamedHierarchy" level="trace">   //Logger的命名和类的命名又有关联的,如果我们在配置文件中配置一个Logger的名称为              

                                                                                                        com.demo.NamedHierarchy   //

                                                                      那么类com.demo.NamedHierarchy中的Logger就会匹配到这一配置,同时所有父节点的配置也会被适用。

                                       也就是说类com.demo.NamedHierarchy   将会引用com.demo.NamedHierarchy,com.demo,root这三个Logger


                         如果你不希望LogEvent被按命名层次分别处理,只希望最低一层的子节点处理,那么可以在Logger配置时增加additivity="false",如

                                       <Logger name="com.demo.NamedHierarchy" level="trace" additivity="false">,这样com.demo.NamedHierarchy搜寻到       

                                              com.demo.NamedHierarchy就不往上搜寻其它logger

       <AppenderRef ref="Console"/>  //引用appenders

</Logger>

<Logger name="com.demo" level="debug">

       <AppenderRef ref="Console"/>

</Logger>

    <Root level="error">         //根logger,如果可以按照层次搜寻,都会用到

      <AppenderRef ref="Console"/>

    </Root>    

  </Loggers>

</Configuration>

 

工程结构如下:


运行NamedHierarchy你会发现结果如下:

01:33:48.864 [main] TRACE com.demo.NamedHierarchy - TRACE: Named Hierarchy TRACE

01:33:48.864 [main] TRACE com.demo.NamedHierarchy - TRACE: Named Hierarchy TRACE

01:33:48.864 [main] TRACE com.demo.NamedHierarchy - TRACE: Named Hierarchy TRACE

01:33:48.867 [main] DEBUG com.demo.NamedHierarchy - DEBUG: NamedHierarchy.run TRACE

01:33:48.867 [main] DEBUG com.demo.NamedHierarchy - DEBUG: NamedHierarchy.run TRACE

01:33:48.867 [main] DEBUG com.demo.NamedHierarchy - DEBUG: NamedHierarchy.run TRACE

01:33:48.868 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy TRACE

01:33:48.868 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy TRACE

01:33:48.868 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy TRACE

为什么同样的日志信息会被输出三次呢?这是因为logger的命名符合命名层次规则,而层次关系是由对应的LoggerConfig来维护的。root是整个层次规则(或结构)的顶层,父节点和子节点是通过“.”来识别的,如com.demo是com.demo.NamedHierarchy的父节点,com.demo.NamedHierarchy是com.demo的子节点。

同时Logger的命名和类的命名又有关联的,如果我们在配置文件中配置一个Logger的名称为com.demo.NamedHierarchy,那么类com.demo.NamedHierarchy中的Logger就会匹配到这一配置,同时所有父节点的配置也会被适用。所以在我们使用logger.trace("TRACE: " + nh + " " + logger.getLevel()); 输出日志时,配置文件中3Logger对应的Appender分别被调用。

如果你把

<Logger name="com.demo.NamedHierarchy" level="trace">

修改为

<Logger name="com.demo.NamedHierarchy" level="error">   按最低层的过滤级别过滤


运行,结果如下:

21:40:44.389 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy ERROR

21:40:44.389 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy ERROR

21:40:44.389 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy ERROR

为什么父节点的Appender没有输出?这是由于LogEventlevelLoggerConfiglevel在特定组合下,LogEvent不会被继续向下转发处理,组合关系如下,其中YES表示转发继续处理,NO表示不继续转发。

 

Event Level

LoggerConfig Level

TRACE

DEBUG

INFO

WARN

ERROR

FATAL

OFF

ALL

YES

YES

YES

YES

YES

YES

NO

TRACE

YES

NO

NO

NO

NO

NO

NO

DEBUG

YES

YES

NO

NO

NO

NO

NO

INFO

YES

YES

YES

NO

NO

NO

NO

WARN

YES

YES

YES

YES

NO

NO

NO

ERROR

YES

YES

YES

YES

YES

NO

NO

FATAL

YES

YES

YES

YES

YES

YES

NO

OFF

NO

NO

NO

NO

NO

NO

NO

 

如果你不希望LogEvent被按命名层次分别处理,只希望最低一层的子节点处理,那么可以在Logger配置时增加additivity="false",如:

<Logger name="com.demo.NamedHierarchy" level="trace" additivity="false">

       <AppenderRef ref="Console"/>

</Logger>

 

4、定时重新加载配置

Log4j2支持定时检查配置文件是否变化并根据变化重新加载,这个功能在实际应用中比较有价值,比如产品上网后有问题,如果默认的error级别的日志不能支撑定位,需要切换到trace级别,定时加载的功能就可以避免重启服务,毕竟商用产品重启服务代价还是很大的,有时候还必须先获取客户的授权。

Configuration中增加monitorInterval="30"参数,其中3030秒,如下:

<Configuration monitorInterval="30">

...

</Configuration>

 

5、常用的Appender

关于详细的Appender及配置参数,建议查看APIhttp://logging.apache.org/log4j/2.x/manual/appenders.html

5.1 FileAppender

FileAppender支持把日志信息写入文件,典型的配置如下:

append用来设置程序开始时日志是否被追加到原日志文件上,fileName表示要保存的文件名称,bufferedIObufferSize表示将日志内容缓存到bufferSize大小后写入文件:

<?xml version="1.0" encoding="UTF-8"?>

<Configuration>

  <Appenders>

    <File name="MyFile" append="true" fileName="logs/mylog.log" bufferedIO="true" bufferSize="512">

      <PatternLayout>

        <Pattern>%d{MM-dd-yyyy} %p %c{1.} [%t] %m%n</Pattern>

      </PatternLayout>

    </File>

  </Appenders>

  <Loggers>

    <Root level="error">

      <AppenderRef ref="MyFile"/>

    </Root>

  </Loggers>

</Configuration>


如果上层输出位置和下层输出位置不同。将会定位不到


5.2 RollingFileAppender

循环写入文件,典型配置如下:

以下的配置可以简单概括为:初始日志名称是rolling.log,当rolling.log日志文件达到1KB时,将rolling.log修改为app-日期-1.log并压缩为app-日期-1.log.gzrolling.log重新开始写;当再次达到1KB时,将rolling.log修改为app-日期-2.log并压缩为app-日期-2.log.gzrolling.log重新开始写;当再次达到1KB时,删除app-日期-1.log.gz,修改app-日期-2.log.gzapp-日期-1.log.gz,将rolling.log修改为app-日期-2.log并压缩为app-日期-2.log.gzrolling.log重新开始写;

<?xml version="1.0" encoding="UTF-8"?>

<Configuration>

  <Appenders>

    <RollingFile name="RollingFile" fileName="logs/rolling.log"

                 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">

      <PatternLayout>

        <Pattern>%d{MM-dd-yyyy} %p %c{1.} [%t] %m%n</Pattern>

      </PatternLayout>

      <Policies>

        <TimeBasedTriggeringPolicy />

        <SizeBasedTriggeringPolicy size="1 KB"/>

      </Policies>

      <DefaultRolloverStrategy fileIndex="max" max="2"/>

    </RollingFile>

  </Appenders>

  <Loggers>

    <Root level="error">

      <AppenderRef ref="RollingFile"/>

    </Root>

  </Loggers>

</Configuration>

建议你使用此配置写一个简单的脚步验证效果。


AsyncAppender

  1. <Configuration name="LinkedTransferQueueExample">
  2. <Appenders>
  3. <List name="List"/>
  4. <Async name="Async" bufferSize="262144">
  5. <AppenderRef ref="List"/>
  6. <LinkedTransferQueue/>
  7. </Async>
  8. </Appenders>
  9. <Loggers>
  10. <Root>
  11. <AppenderRef ref="Async"/>
  12. </Root>
  13. </Loggers>
  14. </Configuration>
  15. <?xml version="1.0" encoding="UTF-8"?>

    ConsoleAppender

      • <Configuration status="warn" name="MyApp" packages="">


    1.  <Appenders>
    2. <Console name="STDOUT" target="SYSTEM_OUT">
    3. <PatternLayout pattern="%m%n"/>
    4. </Console>
    5. </Appenders>
    6. <Loggers>
    7. <Root level="error">
    8. <AppenderRef ref="STDOUT"/>
    9. </Root>
    10. </Loggers>
    11. </Configuration>

    更多详细内容,请查看官方文档:http://logging.apache.org/log4j/2.x/manual/architecture.html

    
    
    
    
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值