log4j2详解

log4j是一个java的日志工具, log4j2是它的升级版

http://logging.apache.org/log4j/2.x/

概述

本文主要讨论 log4j2.

log4j2 的核心概念是 日志等级 Logger, 日志格式 PatternLayout 和 日志输出(目的地) Appender.

  • Logger - 表示输出的日志等级
    1. fatal - 致命
    2. error - 错误
    3. warn - 警告
    4. info - 信息
    5. debug - 调试
    6. trace - 跟踪
    7. all - 全部
  • PatternLayout
  • Appender - 表示日志输出的目的地, 比如 控制台, 文件. 数据库等

也包括 Filter 等.

入个门

安装

gradle引用 参考

1
2
3
4
dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.14.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.14.0'
}

maven

1
2
3
4
5
6
7
8
9
10
11
12
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.0</version>
</dependency>
</dependencies>

直接使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.log4j2;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;

public class TestLog4j2 {

// TestLog4j2.class 等价于 TestLog4j2.class.getName() 即为 "com.log4j2.TestLog4j2"
// 表示将以此字符串(该类的完全限定名称)为日子输出前缀
// private static Logger logger = LogManager.getLogger(TestLog4j2.class);
private static Logger logger = LogManager.getLogger(TestLog4j2.class.getName());

@Test
public void error() {
logger.fatal("fatal 致命错误");
logger.error("error 错误");
logger.warn("warn 警告");
logger.info("info 信息");
logger.debug("debug 调试");
logger.trace("trace 跟踪");

}


}

默认无配置的 输出

1
2
21:13:25.422 [Test worker] FATAL com.log4j2.TestLog4j2 - fatal 致命错误
21:13:25.438 [Test worker] ERROR com.log4j2.TestLog4j2 - error 错误

不配置直接使用, 得到的就是 error 及以上日志级别 的输出, 其他级别屏蔽.

使用代码配置自定义日志输出等级

官方手册配置篇未有提及使用代码控制

参考

强转, 对就是强转, 不过要注意是 org.apache.logging.log4j.core.Logger, 不是 org.apache.logging.log4j.Logger

分析源码出来的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.log4j2;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import org.junit.jupiter.api.Test;

public class TestLog4j2 {

// TestLog4j2.class 等价于 TestLog4j2.class.getName() 即为 "com.log4j2.TestLog4j2"
// 表示将以此字符串(该类的完全限定名称)为日子输出前缀
// private static Logger logger = LogManager.getLogger(TestLog4j2.class);
private static Logger logger = (Logger) LogManager.getLogger(TestLog4j2.class);

@Test
public void error() {
logger.setLevel(Level.ALL);
logger.fatal("fatal 致命错误");
logger.error("error 错误");
logger.warn("warn 警告");
logger.info("info 信息");
logger.debug("debug 调试");
logger.trace("trace 跟踪");
}


}

自定义日志等级

log4j2 以int数字分级, 数字越大, 级别越那个啥~ 说高也行说低也行.

粽子数字越大输出越多!

参考

Standard Level intLevel
OFF 0
FATAL 100
ERROR 200
WARN 300
INFO 400
DEBUG 500
TRACE 600
ALL Integer.MAX_VALUE

这是定义好的

在 Level.java 中以静态变量的形式提供

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public static final Level OFF;

/**
* A severe error that will prevent the application from continuing.
*/
public static final Level FATAL;

/**
* An error in the application, possibly recoverable.
*/
public static final Level ERROR;

/**
* An event that might possible lead to an error.
*/
public static final Level WARN;

/**
* An event for informational purposes.
*/
public static final Level INFO;

/**
* A general debugging event.
*/
public static final Level DEBUG;

/**
* A fine-grained debug message, typically capturing the flow through the application.
*/
public static final Level TRACE;

/**
* All events should be logged.
*/
public static final Level ALL;

/**
* @since 2.1
*/
public static final String CATEGORY = "Level";

private static final ConcurrentMap<String, Level> LEVELS = new ConcurrentHashMap<>(); // SUPPRESS CHECKSTYLE

private static final long serialVersionUID = 1581082L;

static {
OFF = new Level("OFF", StandardLevel.OFF.intLevel());
FATAL = new Level("FATAL", StandardLevel.FATAL.intLevel());
ERROR = new Level("ERROR", StandardLevel.ERROR.intLevel());
WARN = new Level("WARN", StandardLevel.WARN.intLevel());
INFO = new Level("INFO", StandardLevel.INFO.intLevel());
DEBUG = new Level("DEBUG", StandardLevel.DEBUG.intLevel());
TRACE = new Level("TRACE", StandardLevel.TRACE.intLevel());
ALL = new Level("ALL", StandardLevel.ALL.intLevel());
}

自定义的话就是 Level.forName() 方法进行创建, 参考官方手册

1
Level.forName("DIAG", 550);

对比上表, 可知 DEBUG 及以上都会被输出.

使用配置文件

对于不配置, 直接使用. 也就是默认的, 等效的配置为, 参考

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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>

(第一次用这个, 我猜)

不管是在log4j中, 还是在log4j2中, 大都是使用配置文件的. 那么如何使用?

  1. Log4j will inspect the “log4j.configurationFile” system property and, if set, will attempt to load the configuration using the ConfigurationFactory that matches the file extension. Note that this is not restricted to a location on the local file system and may contain a URL.
  2. If no system property is set the properties ConfigurationFactory will look for log4j2-test.properties in the classpath.
  3. If no such file is found the YAML ConfigurationFactory will look for log4j2-test.yaml or log4j2-test.yml in the classpath.
  4. If no such file is found the JSON ConfigurationFactory will look for log4j2-test.json or log4j2-test.jsn in the classpath.
  5. If no such file is found the XML ConfigurationFactory will look for log4j2-test.xml in the classpath.
  6. If a test file cannot be located the properties ConfigurationFactory will look for log4j2.properties on the classpath.
  7. If a properties file cannot be located the YAML ConfigurationFactory will look for log4j2.yaml or log4j2.yml on the classpath.
  8. If a YAML file cannot be located the JSON ConfigurationFactory will look for log4j2.json or log4j2.jsn on the classpath.
  9. If a JSON file cannot be located the XML ConfigurationFactory will try to locate log4j2.xml on the classpath.
  10. If no configuration file could be located the DefaultConfiguration will be used. This will cause logging output to go to the console.

上面引用自官方手册, 大概就是就是, 要使用配置文件, 你需要在 classpath 中(一般就是resources目录)创建一个特殊文件名的文件, 例如: log4j2.xml, 再其中进行配置, 然后 log4j2 会自动读取解析配置.

再解释清除点吧, 上面官方的说法有三种处理方式

  1. 先看有没有 “log4j.configurationFile” 的系统变量, 有就是用它的值作为配置文件路径进行操作.
  2. 然后如果没有就在 classpath 中查找 特定文件名称的配置文件
  3. 如果也没有任何的配置文件, 那么就在不找了, 直接 STDOUT
  4. 然后就是log4j2支持多种配置文件格式, properties, json, yaml, xml.

个人推荐使用 xml 文件格式配置, 理由如下(我有点强迫症)

  1. 官方介绍中, 主要以xml格式配置为例
  2. 使用xml配置, 有代码提示(虽然不常用, 一次配置终身使用), 当然它这个 schema 描述是不完整的

在IDEA中使能代码提示

image-20201228231747177

image-20201228231855344

image-20201228232057591

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">
<!-- 之后在这里添加配置 -->
<Appenders>
<Console name="Console" target="STDOUT">
<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>

自定义配置

实测, 代码提示无用, 官方似乎并没有维护它(xsd), 不好用.

不过发现一个更好的方式, 就是直接到 org.apache.logging.log4j.core.appender 这个包中查找, 属性, 对应的解释都有.

将日志存到文件

  • 将全部级别日志导入到 logs/log_all.log 文件中

    image-20201229162121558

    image-20201229171000653

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <?xml version="1.0" encoding="UTF-8" ?>
    <Configuration name="配置的名字" xmlns="http://logging.apache.org/log4j/2.0/config">
    <Properties>

    </Properties>

    <CustomLevels>

    </CustomLevels>
    <!-- 之后在这里添加配置 -->
    <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="MyFile" fileName="logs/log_all.log">
    <PatternLayout>
    <Pattern>%d %p %c [%t] %m%n</Pattern>
    </PatternLayout>
    </File>
    </Appenders>
    <Loggers>
    <Root level="trace">
    <AppenderRef ref="Console" level="info"/>
    <AppenderRef ref="MyFile" level="trace"/>
    </Root>
    </Loggers>
    </Configuration>

未完待续