Bootstrap

Log4j2

一 简介

历史上出现了很多的日记框架,如:

  • Log4j:Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。
  • Log4j 2:Apache Log4j 2是apache开发的一款Log4j的升级产品。
  • Commons Logging:Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging。
  • Slf4j:类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)。
  • Logback:一套日志组件的实现(Slf4j阵营)。
  • Jul(Java Util Logging):自Java1.4以来的官方日志实现。

由于java官方日记框架Jul出现较晚,因此没能统一日记接口。slf4j和commons-loggings都只定义了接口,为了桥接其他日记框架,需要额外的jar包。使用日记接口,可以方便的在不同日记框架间切换(为了灵活性的同时也付出了一定代价),于是形成了两大阵容:
在这里插入图片描述
一般常见的使用组合为:slf4j与logback,commons logging与log4j。但是我选择使用Log4j2,它重写了log4j,具有Logback的全部特性,是log4j的升级版,却不兼容log4j。log4j2将接口(log4j-api)和实现(log4j-core)分开来,提供了桥接其他日记实现的可能(log4j-core被适配器替换)。log4j2提供了与Jul、Slf4j、commons logging桥接的jar包,因此log4j2即使不兼容log4j,也能通过commons logging桥接包使用它。与slf4j的桥接如下:
在这里插入图片描述
除此之外,log4j2还有很多特性,如异步输出(降低io负担),自动加载配置(避免重启应用),自定义日记级别(感觉不常用)等等。

二 架构

2.1 主要组件

log4j中使用的类大致如下:
在这里插入图片描述

如果看不懂UML,请参考UML类图

Logger是最常使用的类,用于打印日记的接口,通过LogManager类指定名字获得。LogManager定位LoggerContext并从它那获得Logger。如果Logger被创建,Logger会被关联一个LoggerConfig,该LoggerConfig可能与Logger同名,或同父package名或为root LoggerConfig(涉及Level Inheritance)。

使用Logger可以打印不同级别的日记,这些日记会被包装为LogEvent。LogEvent会被派送到LoggerConfig上。LoggerConfig在xml配置文件中由Logger元素配置的,LoggerConfig含有日记级别(Log Level)信息,对应0到多个Appender。LoggerConfig根据自己的日记级别配置与LogEvent的级别,决定是否允许进一步的处理。如果NO则丢弃,如果Yes则传给Appender。

LoggerConfig中的日记级别只是一个种定义好了的过滤器(Filter),还可以在Logger元素中为LoggerConfig配置过滤器,进行更细致的控制。

Appender负责将LogEvent派送到目的地,可以有很多目的地,如console,文件、远程服务器或数据库等等。一个loggerConfig可以对应很多Appender,loggerConfig含有父(或祖先)loggerConfig的引用。因此loggerConfig不仅将LogEvent发送给自己的所有Appender,还发给它的父(或祖先)LoggerConfig的appender,然后递归向上,这种行为被称为Additivity

举个例子,名为"com.foo"的loggerConfig是名为"com.foo.Bar"的父亲。com.foo配置输出到文件中,com.foo.Bar配置输出到console,那么对应com.foor.Bar的loggerConfig的Logger打印日记时,会同时打印到文件和控制台中。

appender只关心如何将LogEvent送到目的地,而Layout负责格式化LogEvent。log4j中含有不同种Layout,用于不同的用途,如JSON,XML,HTML等等。

比如默认使用PatternLayout,使用类似c语言printf的转化模式(conversion pattern)。例如,一个模式%r [%t] %-5p %c - %m%n会输入如下信息:
176 [main] INFO org.foo.Bar - Located nearest gas station.
分别对应:项目开始到现在的毫秒;打印日记的线程;日记级别;日记对应的Logger名;日记信息

至于LoggerContext和Configuration。LoggerContext是真正产生Logger的地方,在日记系统中扮演很重要的角色。Configuration是一个配置类,如果没有给出配置,则会使用默认Configuration。如果有配置文件,并且在运行时改变该配置文件,log4j会检测到,并生成新的Configuration,所有的Logger都被重定向到新Configuration中的内容,老的Configuration被丢弃。

2.2 层次结构

每个Logger都有自己的名字,通常使用Logger所处类的全限定名作为Logger的名字。LoggerConfig也是一个命名的实体,通常名字与Logger对应。因此log4j中有两个名字层级结构。

如果两者完全匹配,则Logger关联到匹配的LoggerConfig上,使用它的配置。如果没有完全匹配的,Logger会在名字空间上寻找最近匹配的LoggerConfig,并关联它。

在log4j中必定存在root LoggerConfig,即使没有手动配置,也会使用默认的,保证Logger能够关联到LoggerConfig。

2.3 日记级别

LoggerConfig需要配置日记级别,用于筛选某个范围的所有日记。下面给出每种级别的日记是否能够通过不同LoggerConfig的表格:
在这里插入图片描述

三 配置

3.1 查找配置

log4j在初始化时会自动查找配置,然后配置自己。支持各种方式、各种类型的配置,检查过程如下:

  1. 系统属性log4j.configurationFile指定的文件
  2. classpath下log4j2-test.properties
  3. classpath下log4j2-test.yamllog4j2-test.jsonlog4j2-test.xml
  4. classpath下log4j2.properties
  5. classpath下log4j2.yamllog4j2.jsonlog4j2.xml
  6. 默认配置被使用

3.2 简单配置

如果不配置时,log4j会使用默认配置,默认配置对应的xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>
  • 其中Loggers元素中的子元素Root、Logger都是在配置LoggerConfig,因此会配置有0个或多个appender。
  • log4j 的xml语法格式不太严格,参考:XML Syntax

上面配置了Root LoggerConfig,和输出到console的appender。可以为具体的Logger配置一个LoggerConfig,有不同的日记级别:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Logger name="com.foo.Bar" level="trace">
    </Logger>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

由于additivity,com.foo.Bar的LoggerConfig会使用祖先root LoggerConfig的appender,即输出到console中。

3.3 Configuration

Configuration元素一些重要的属性如下:

  • status:log4j框架内部要输出到console的LogEvent的级别。可选值:trace", “debug”, “info”, “warn”, “error” and “fatal”。貌似默认warn。
  • dest:输出到console具体的流。可选值:“err”,“out”,文件或url。默认out。
  • monitorInterval:多少秒扫描一下配置文件

参考:Configuration

3.4 其他配置链接

配置方式官方文档说的很详细,这里直接贴出链接。。。阅读时记住,xml配置的语法很松懈。

ConsoleAppender是比较常用的appender

PatternLayout是一个比较常用的layout。这里要注意使用charset属性日记乱码,PatternLayout默认使用系统编码。

四 使用

使用例子如下:

public class WXTest {
    //声明为静态字段,避免浪费计算资源
    private static final Logger logger=LogManager.getLogger();//无参数构造函数,默认类的全限定名作为Logger名
    @Test
    public void test()  {
        try {
            log(1);
        } catch (Exception e) {
            logger.catching(e);
        }
    }
    public void log(int p) throws Exception {
        logger.info("进入log方法");
        if(p==1){
            throw new Exception("出现异常");
        }
        logger.info("正常退出log方法");
    }
}

输出:

16:32:45.976 [main] INFO  com.luo.WXShop.test.WXTest - 进入log方法
16:32:46.006 [main] ERROR com.luo.WXShop.test.WXTest - Catching
java.lang.Exception: 出现异常
	at com.luo.WXShop.test.WXTest.log(WXTest.java:35) ~[test-classes/:?]
	at com.luo.WXShop.test.WXTest.test(WXTest.java:27) [test-classes/:?]

五 其他

5.1 日记级别使用情景

  • ALL 最低等级的,用于打开所有日志记录。
  • TRACE 很低的日志级别,一般不会使用。
  • DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
  • INFO 消息在粗粒度级别上突出强调应用程序的运行过程。这个可以用于生产环境中输出程序运行的一些重要信息。
  • WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给开发者的一些提示。
  • ERROR 指出发生错误的信息,可能会导致系统出错或是宕机等,必须要避免
  • FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
  • OFF 最高等级,用于关闭所有日志记录。

参考

;