优雅灵活记录Java日志 By log4j2

2017-08-26  本文已影响1481人  LilacZiyun

log4j是一个被广泛使用的Java日志记录框架,通过使用该框架,我们可以在自己的项目中根据自身需求灵活配置日志输出格式,从而获得期望格式的日志信息,用于后续分析、错误排查等。log4j2则是原有log4j的升级版本,该版本使用更加简洁方便。

log4j2使用步骤

注:小编我目前使用的 IDE 为 Intellij,自从写Android代码时使用了Android Studio后,就爱上了 Intellij 这一系列的产品了。

  1. 下载 log4j2 的JAR包:从http://logging.apache.org/log4j/2.x/download.html 官网下载最新版Apache Log4j 2 binary 压缩包,解压后会得到许多JAR包,只需要将其中的 log4j-core-2.7.jar 和 log4j-api-2.7.jar 添加到项目中即可;
  2. 在项目的 src 文件夹下添加 log4j2.xml 文件,该文件为 log4j2 的配置文件,默认文件内容为:
<?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>
  1. 在项目中使用 log4j2:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogTest {
    // 获取 Logger 实例
    static Logger logger = LogManager.getLogger();
    public static void main(String[] args) {

        logger.trace("I am a trace message");
        logger.warn("I am a warn message");
        logger.error("I am a error message");
        logger.info("I am a info message");
        logger.fatal("I am a fatal message");
    }
}

效果如下图所示:

日志效果图-1

咦?上面明明定义了五条日志信息,怎么控制台就显示了两条呢?细致的读者maybe会有如此困惑。小小剧透一波:此玄机存在于 log4j 的配置文件中,若想一探究竟,就继续随我一起仔细探究吧!

log4j2 日志级别

log4j2 中默认的日志级别为:trace < debug < info < warn < error < fatal
当设置了日志输出级别时,当前级别及以上级别的日志会输出,而当前级别以下级别的日志则不会输出,系统默认输出级别为 error,也就是说默认设置下,只有 error 和 fatal这两级日志会输出,这也就解释了为什么上面只输出了两条日志信息

log4j2 日志组件

下图是Apache官网贴出的log4j的类图,通过该类图可以清晰地看出log4j的类层次结构。

log4j2类层次结构图

由类图可以看出:log4j2中主要包含如下概念/组成部分:Loggerontext、Configuration、Filter、Logger、LoggerConfig、Appender、Layout等,后文会详细解释这些概念。

log4j2 由以下三个核心组件组成:

当Logger记录一个事件时,它将事件转发给适当的Appender。然后Appender使用Layout来对日志记录进行格式化,并将其发送给控制台、文件或其它目标位置。另外,Filters可以让你进一步指定一个Appender是否可以应用在一条特定的日志记录上。在日志配置中,Filters并不是必需的,但可以让你更灵活地控制日志消息的流动。

log4j2核心概念

Loggerontext
LoggerContext在Logger系统中扮演着锚点的角色,一般来说,一个应用只会存在于一个LoggerContext中,但是也可以根据使用场景的差异和项目的具体需求,为一个项目配置多个不同的LoggerContext。在同一个LoggerContext下,log系统是可以互通的。

Configuration
Configuration顾名思义,即是当前LoggerContext中的所有Logger的配置环境,每一个LoggerContext均会拥有一个动态可配置的Configuration,该Configuration 包含了当前LoggerContext环境中所有的Loggers、Appenders、Filters、Layouts等配置信息。注意:在reConfiguration期间,新旧Configuration均会同时存在,然而一旦重配过程结束,旧的Configuration就会失效,配置信息会重定向至新的Configuration中。

Logger
Logger是一个通过给LoggerManager.getLogger()方法传递特定的Logger名称而获得的一个AbstractLogger实现类对象,该对象自身并不具体进行任何操作,而是通过关联一个LoggerConfig完成具体的Logger配置,并通过实现AbstractLogger的方法进行具体的操作。注意:通过同一个名称获得的Logger对象会指向同一个Logger引用。

LoggerConfig
LoggerConfig包含了一个Logger对象的具体配置信息,如该Logger关联的Appenders、Filters、过滤级别等。

Filter
过滤器,定义LogEvent的过滤规则。log4j中定义了三种过滤状态:Accept(接受)、Deny(拒绝)和Nertual(中立)。
Accept:该LogEvent将被执行而无需调用其它过滤器;
Deny:忽略当前LogEvent,并将该LogEvent的控制权移交给过滤器调用者;
Nertual:中立,也就是说,当前LogEvent应该传递给其它过滤器,如果没有别的过滤器可以传递了,那么就由现在这个过滤器来处理。

Appender
Appender意为输出目的地,负责将日志消息转发给期望的输出。它负责接收日志事件,使用Layout格式化事件,然后将其发送给对应的目标。对于一个日志事件,我们可以使用多个Appenders来将事件发送到不同的目标位置。例如,我们可以在控制台上显示一个简单的日志事件的同时,将其通过邮件的方式发送给指定的接收者。目前,Appender可以是console、文件、远程socket服务器、Apache Flume、JMS以及远程 UNIX 系统日志守护进程等。

注意:
在某一个Logger中被启用的log请求将被转发到该Logger相关联的的所有Appenders上,并且还会被转发到LoggerConfig的父级的Appenders上。由此可知,如果设置不当的话,会产生一系列的遗传反应。如:Logger A 继承自 Logger B,并且两者均是root的子节点,若LoggerConfig B 中定义了一个文件作为Appender的话,那么使用LoggerConfig A和LoggerConfig B的logger 的log请求都会在该文件中打印,文件中便会显示很多重复的日志信息,这会给日志分析带来不必要的麻烦。还好这是可以被避免的,通过设置 Appender 的 additivity属性为false即可。(默认情况下,additivity="true")

Layout:
Layout用于定义LogEvent的输出格式。

log4j2配置方式

log4j2 有如下四种配置方式,可以根据你的意愿、喜好等自行选择:

  1. 通过配置文件进行配置,配置文件可以是 XML、 JSON、 YAML 和 properties这四种类型中的任意一种;
  2. 在代码中创建 ConfigurationFactory 和 Configuration 累的实现类;
  3. 在代码中调用Configuration 接口的 API 在默认配置类上添加组件;
  4. 在代码中调用内部类 Logger 的方法实现自定义。

通过配置文件配置log4j

目前小编还只使用了文件的配置方式,所以本文着重于通过配置文件配置log4j,以后有机会再好好研究一波代码配置的方式,然后与看官分享 _

文件配置优先级

对应于四类配置文件:XML、 JSON、 YAML 和 properties,Log4j 分别有与之相应的 ConfigurationFactory 实现类,不同的实现类可以加载不同扩展名的配置文件中的配置信息。当 Log4j 启动时会按照一定的优先级顺序在classpath(一般是项目的src文件夹下)查找项目中的配置文件,若找到一个配置文件,就调用与当前文件扩展名对应的ConfigurationFactory实现类加载该配置文件中的配置信息,否则继续查找下一优先级的配置文件,若未找到任何配置文件,就使用默认配置DefaultConfiguration。
不同配置文件的优先级如下图所示:

配置文件优先级

配置文件详解

如下是个比较完整详细的 XML 形式的配置文件,该文件通过注释的方式提供简要解释以便于理解。

<?xml version="1.0" encoding="UTF-8"?>
<!-- configuration 有多个属性,常用的有:name(配置名)
status(是否记录log4j2本身的event信息,默认是OFF,
可选值有: "trace", "debug", "info", "warn", "error" and "fatal")
dest(错误流输出位置,标准错误流、文件或远程邮件发送)
strict(是否使用strict xml形式,configuration支持concise(简约)和strict(严格)两种模式的xml。
简约模式下,使得文件编写起来更简洁) -->
<configuration status="OFF">
    <!-- 定义如下几个引用名,用于后面配置文件中使用 -->
    <Properties>
        <property name="log_pattern">%d{yyyy-MM-dd HH:mm:ss z} %-5level %class{36}%L%M - %msg%xEx%n
</property><!-- 日志输出格式 -->
        <property name="log-path">${web:rootDir}/logs</property><!-- ${web:rootDir}是项目根目录 -->
        <property name="every_file_size">5M</property><!-- 日志切割的最小单位 -->
        <property name="output_log_level">debug</property><!-- 日志输出级别 -->
    </Properties>

    <!-- 先定义所有的appender(日志输出位置) -->
    <appenders>

        <!-- 输出到控制台 name: 当前appender名 target: 目的位置-->
        <Console name="Console" target="SYSTEM_OUT">
            <!-- ThresholdFilter: 用于定义过滤机制 -->
            <!-- level: 日志过滤级别 -->
            <!-- onMatch="ACCEPT":保留level 及以上级别的日志 -->
            <!-- onMismatch="DENY":丢掉level 以下级别的日志-->
            <!-- onMatch 和 onMissmatch 可选值为:ACCEPT DENY NEUTRAL-->
            <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY" />

            <!--这个都知道是输出日志的格式 -->
            <PatternLayout pattern="${log_pattern}" />
        </Console>

        <!-- debug级别日志文件 -->
        <!-- RollingFile:日志滚动输出 -->
        <!--每次大小超过size,则这size大小的日志会自动进行压缩,作为存档 -->
        <RollingFile name="app_debug" fileName="${log-path}/debug/debug.log" 
filePattern="${log-path}/debug/debug-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL" />
                <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="NEUTRAL" />
            </Filters>
            <PatternLayout pattern="${log_pattern}" />
            <!-- SizeBasedTriggeringPolicy: 基于日志大小切分日志 -->
            <SizeBasedTriggeringPolicy size="${every_file_size}"/>
        </RollingFile>

        <!-- info级别日志文件 -->
        <RollingFile name="app_info" fileName="${log-path}/info/info.log" 
filePattern="${log-path}/info/info-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL" />
                <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <PatternLayout pattern="${log_pattern}" />
            <SizeBasedTriggeringPolicy size="${every_file_size}"/>
        </RollingFile>

        <!-- error级别日志文件 -->
        <RollingFile name="app_error" fileName="${log-path}/error/error.log" 
filePattern="${log-path}/error/error-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <PatternLayout pattern="${log_pattern}" />
            <SizeBasedTriggeringPolicy size="${every_file_size}"/>
        </RollingFile>

    </appenders>

    <!-- 定义logger,只有定义了logger并引入之前定义的appender,appender才会生效 -->
    <loggers>
        <!--建立一个默认的root的logger,需要在root的level中指定输出的级别, -->
        <root level="${output_log_level}">
            <appender-ref ref="Console" />
            <appender-ref ref="app_debug"/>
            <appender-ref ref="app_info"/>
            <appender-ref ref="app_error"/>
        </root>
    </loggers>

</configuration>

log4j2 配置节点分析

configuration

configuration决定了当前上下文的loggers配置信息,是配置文件根节点,主要包含如下属性值:

Appenders

Appenders用于定义当前LoggerContext中所需要使用到的Appender。目前log4j2提供了多种不同类型的appender可供配置。如下介绍几种常用的,如果想了解更全面的信息,可移步官网

Appender类型

ConsoleAppender:
ConsoleAppender是最常用的Appenders之一,它只是将日志消息显示到控制台上。log4j2的默认Appender即为ConsoleAppender。

ConsoleAppender参数如下:

FileAppender:
FileAppenders将日志记录写入到文件中,它负责打开、关闭文件,向文件中追加日志记录,并对文件进行加锁,以免数据被破坏或者覆盖。
FileAppender参数如下:

RollingFileAppender

滚动输出日志到文件中,RollingFileAppender 根据TriggeringPolicy 和RolloverPolicy滚动将日志事件输出到fileName指定的文件中。TriggeringPolicy用于决定是否触发RolloverPolicy所定义的日志滚动操作,若未设置RolloverPolicy ,则会使用默认设置 DefaultRolloverStrategy。

RollingFileAppender参数如下:

其它Appender:
SyslogAppenders将日志记录发送给本地或者远程系统的日志服务;SMTPAppender会将日志内容以邮件的形式发送出去;FailoverAppender设置在处理日志的过程中,如果一个或者多个Appender失败,自动切换到其他Appender上等,更多信息详见官网

Layout

log4j2中使用较多的Layout为PatternLayout,格式为:

<PatternLayout pattern = "%d{yyyy-MM-dd HH:mm:ss z} %-5level %class{36}%L%M - %msg%xEx%n" />

%d{HH:mm:ss:SSS}:日志输出时间,精确到毫秒
%t:当前线程名称
%-5level:日志级别,-5表示左对齐并固定输出5个字符,如果不足右边补零
%logger:logger名称
%msg:日志文本
%n:换行
%F:文件所在的类文件名
%L:行号
%M:所在方法名
%l:语句所在的行数,包括类名,方法名,文件名,行数

上一篇 下一篇

猜你喜欢

热点阅读