Log4j 2体系结构 [2] - 配置
Log4j 2.x允许用户通过配置文件或编程的方式来进行配置:
- 通过配置文件,例如
log4j2.xml
、log4j2.json
、log4j2.yaml
、或log4j2.properties
。 - 通过编程的方式,创建
ConfigurationFactory
和Configuration
的实现。 - 通过编程的方式,调用
Configuration
接口暴露的API,来添加组件到默认配置中。 - 通过编程的方式,调用内部
Logger
类的方法。
更多关于程序化配置Log4j 2.x的信息,请参考Extending Log4j 2和Programmatic Log4j Configuration。
Note that unlike Log4j 1.x, the public Log4j 2 API does not expose methods to add, modify or remove appenders and filters or manipulate the configuration in any way.
与Log4j 1.x不同的是,Log4j 2.x没有暴露任何添加、修改或删除Appender
和Filter
的方法,也没有操纵Configuration
的方法。
自动化配置
初始化时,Log4j 2.x会根据一定的策略进行自动化配置。Log4j 2.x中提供了4个ConfigurationFactory
实现,分别用于处理JSON、YAML、.properties
、和XML文件。
- Log4j 2.x会检查系统变量
log4j.configurationFile
,如果设置过该变量,则根据变量值指定的文件后缀来调用响应的ConfigurationFactory
实现来处理配置。 - 如果步骤1中的系统变量未设置,
properties ConfigurationFactory
会在classpath中查找log4j2-test.properties
- 如果步骤2中的文件未找到,
YAML ConfigurationFactory
会在classpath中查找log4j2-test.yaml
或log4j2-test.yml
- 如果步骤3中的文件未找到,
JSON ConfigurationFactory
会在classpath中查找log4j2-test.json
或log4j2-test.jsn
- 如果步骤4中的文件未找到,
XML ConfigurationFactory
会在classpath中查找log4j2-test.xml
- 如果步骤2-5中的测试文件都未找到,
properties ConfigurationFactory
会在classpath中查找log4j2.properties
- 如果步骤6中的文件未找到,
YAML ConfigurationFactory
会在classpath中查找log4j2.yaml
或log4j2.yml
- 如果步骤7中的文件未找到,
JSON ConfigurationFactory
会在classpath中查找log4j2.json
或log4j2.jsn
- 如果步骤8中的文件未找到,
XML ConfigurationFactory
会在classpath中查找log4j2.xml
- 如果步骤6-9中的文件都未找到,将使用
DefaultConfiguration
,即将所有的日志输出到控制台。
相加性配置
在以下的章节中,我将使用下面这个示例来介绍配置是如何影响打印结果的。
import com.foo.Bar;
// Import log4j classes.
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class MyApp {
// Define a static logger variable so that it references the
// Logger instance named "MyApp".
private static final Logger logger = LogManager.getLogger(MyApp.class);
public static void main(final String... args) {
// Set up a simple configuration that logs on the console.
logger.trace("Entering application.");
Bar bar = new Bar();
if (!bar.doIt()) {
logger.error("Didn't do it.");
}
logger.trace("Exiting application.");
}
}
package com.foo;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class Bar {
static final Logger logger = LogManager.getLogger(Bar.class.getName());
public boolean doIt() {
logger.entry();
logger.error("Did it again!");
return logger.exit(false);
}
}
考虑如下的配置:
来自于com.foo.Bar
的所有日志事件都会被打印到控制台,而其他模块的日志事件只有高于ERROR级别的才会被打印到控制台。上述配置的打印结果为:
17:13:01.540 [main] TRACE com.foo.Bar - entry
17:13:01.540 [main] TRACE com.foo.Bar - entry
17:13:01.540 [main] ERROR com.foo.Bar - Did it again!
17:13:01.540 [main] TRACE com.foo.Bar - exit (false)
17:13:01.540 [main] TRACE com.foo.Bar - exit (false)
17:13:01.540 [main] ERROR MyApp - Didn't do it.
可以发现,来自于com.foo.Bar
的日志事件在控制台中打印了两遍。这是由于相加性导致的。(关于相加性更详细的的介绍,可以参考我的另一篇文章[Log4j 2体系结构 [1] - 概念理解](https://segmentfault.com/a/11...)
可以通过配置
的additivity
属性为false
来关闭相加性。例如修改上述配置为
,打印结果就会变为:
17:13:01.540 [main] TRACE com.foo.Bar - entry
17:13:01.540 [main] ERROR com.foo.Bar - Did it again!
17:13:01.540 [main] TRACE com.foo.Bar - exit (false)
17:13:01.540 [main] ERROR MyApp - Didn't do it.
自动重配置
当通过配置文件进行配置时,Log4j 2.x能够自动检测配置文件的改动情况,并自动进行重配置。可以通过
的monitorInterval
来启用该功能。Log4j 2.x检查配置文件是否有改动的时机是:
- a log event is evaluated and/or logged
- the monitorInterval has elapsed since the last check
通过XML进行配置
自2.9版本开始,Log4j 2.x不再支持在XML中处理DTD。如果要将配置分开存储在不同的文件中,可以使用XInclude
和Composite Configuration
(复合配置)。Log4j 2.x支持两种风格的XML写法:concise(简洁的)和strict(严格的)。接下来,用一个例子来展示一下两种写法的区别。
上述两种写法是等价的。不过,严格写法的好处是可以通过XML Schema来验证。
XInclude
Log4j 2.x支持使用XInclude
将配置分散在多个XML文件中。例如:
xinclude-demo.log
log4j-xinclude-appenders.xml
:
%d %p %C{1.} [%t] %m%n
log4j-xinclude-loggers.xml
:
复合配置
除了上面介绍的XInclude
方式外,Log4j 2.x还支持复合配置,即通过log4j.configurationFile
来指定一个配置文件列表,用,
作为分隔符。合并这些配置文件的策略可以通过log4j.mergeStrategy
来指定,其值为一个实现了MergeStrategy
接口的类的全量名。如果未指定策略类,默认的合并逻辑为:
-
Configuration
的属性按照如下规则聚合,位于列表后面的配置将替代位于列表前面的配置。但是status
和monitorInterval
的选择略有不同,status
将选择多个等级中的最高等级,monitorInterval
将选择多个大于0的值的最小值。 -
中定义的属性将合并,并且如果位于列表后面的配置文件会覆盖前面配置中同名的属性值。 - 如果有多个
,它们会被合并到
中。因为Filter未命名,所以
可能会有重复的项。 -
和
将被合并,后覆盖前。 -
将被合并,同名Appender后覆盖前,覆盖涵盖其包含的所有子标签。 -
将被合并,其属性后覆盖前。
中对Appender的引用也将被合并,后覆盖前。如果有多个
,它们会被合并到
中,有可能重复。
里的
会与
的保存或丢弃保持一致。
状态信息
Log4j 2.x中包含了一个StatusLogger
,能够及时地发现配置过程中的问题。
- 2.9版本之后,如果系统属性
log4j2.debug
被定义,Log4j 2.x会打印所有的内部日志 -
2.8及以前的版本,可以通过如下方式设置:
- 在找到配置文件之前,通过系统属性
org.apache.logging.log4j.simplelog.StatusLogger.level
控制 - 在找到配置文件之后,通过
的status
属性。status
的值可以为: "trace"、"debug"、"info"、"warn"、"error"和"fatal"。
- 在找到配置文件之前,通过系统属性
可以通过dest
属性来设置StatusLogger
的日志打印位置,例如dest=err
来将日志打印到stderr。或者可以通过将status
设置为OFF
,再通过编程的方式改变日志输出位置:
StatusConsoleListener listener = new StatusConsoleListener(Level.ERROR);
StatusLogger.getLogger().registerListener(listener);
Maven测试阶段的配置
Log4j 2.x中支持3种方式来配置测试环境中的日志配置:
-
src/test/resources
中放置名为log4j2-test.xml
的配置文件,Log4j 2.x会自动加载该配置,而不会使用classpath
中的log4j2.xml
配置。这就实现了测试与生产环境的配置分离。 - 在测试类上标注
@BeforeClass
来设置log4j.configurationFile
属性的值。 -
使用
LoggerContextRule
JUnit测试规则。这需要将在pom.xml
中加入如下的依赖:org.apache.logging.log4j log4j-core 2.13.0 tests LoggerContextRule
的使用方式如下:import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.test.appender.ListAppender; import org.junit.Rule; import org.junit.Test; import java.util.List; public class AwesomeTest { // LoggerContextRule包含在 log4j-core-2.13.0-tests.jar 中 @Rule public LoggerContextRule init = new LoggerContextRule("MyTestConfig.xml"); @Test public void testSomeAwesomeFeature() { final LoggerContext ctx = init.getLoggerContext(); final Logger logger = init.getLogger("org.apache.logging.log4j.my.awesome.test.logger"); final Configuration cfg = init.getConfiguration(); final ListAppender app = init.getListAppender("List"); logger.warn("Test message"); final List
events = app.getEvents(); // etc. } }