Log4j 2体系结构 [2] - 配置

Log4j 2体系结构 [2] - 配置

Log4j 2.x允许用户通过配置文件或编程的方式来进行配置:

  • 通过配置文件,例如log4j2.xmllog4j2.jsonlog4j2.yaml、或log4j2.properties
  • 通过编程的方式,创建ConfigurationFactoryConfiguration的实现。
  • 通过编程的方式,调用Configuration接口暴露的API,来添加组件到默认配置中。
  • 通过编程的方式,调用内部Logger类的方法。

更多关于程序化配置Log4j 2.x的信息,请参考Extending Log4j 2Programmatic 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没有暴露任何添加、修改或删除 AppenderFilter的方法,也没有操纵 Configuration的方法。

自动化配置

初始化时,Log4j 2.x会根据一定的策略进行自动化配置。Log4j 2.x中提供了4个ConfigurationFactory实现,分别用于处理JSON、YAML、.properties、和XML文件。

  1. Log4j 2.x会检查系统变量log4j.configurationFile,如果设置过该变量,则根据变量值指定的文件后缀来调用响应的ConfigurationFactory实现来处理配置。
  2. 如果步骤1中的系统变量未设置,properties ConfigurationFactory会在classpath中查找log4j2-test.properties
  3. 如果步骤2中的文件未找到,YAML ConfigurationFactory会在classpath中查找log4j2-test.yamllog4j2-test.yml
  4. 如果步骤3中的文件未找到,JSON ConfigurationFactory会在classpath中查找log4j2-test.jsonlog4j2-test.jsn
  5. 如果步骤4中的文件未找到,XML ConfigurationFactory会在classpath中查找log4j2-test.xml
  6. 如果步骤2-5中的测试文件都未找到,properties ConfigurationFactory会在classpath中查找log4j2.properties
  7. 如果步骤6中的文件未找到,YAML ConfigurationFactory会在classpath中查找log4j2.yamllog4j2.yml
  8. 如果步骤7中的文件未找到,JSON ConfigurationFactory会在classpath中查找log4j2.jsonlog4j2.jsn
  9. 如果步骤8中的文件未找到,XML ConfigurationFactory会在classpath中查找log4j2.xml
  10. 如果步骤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。如果要将配置分开存储在不同的文件中,可以使用XIncludeComposite 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接口的类的全量名。如果未指定策略类,默认的合并逻辑为:

  1. Configuration的属性按照如下规则聚合,位于列表后面的配置将替代位于列表前面的配置。但是statusmonitorInterval的选择略有不同,status将选择多个等级中的最高等级,monitorInterval将选择多个大于0的值的最小值。
  2. 中定义的属性将合并,并且如果位于列表后面的配置文件会覆盖前面配置中同名的属性值。
  3. 如果有多个,它们会被合并到中。因为Filter未命名,所以可能会有重复的项。
  4. 将被合并,后覆盖前。
  5. 将被合并,同名Appender后覆盖前,覆盖涵盖其包含的所有子标签。
  6. 将被合并,其属性后覆盖前。中对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种方式来配置测试环境中的日志配置:

  1. src/test/resources中放置名为log4j2-test.xml的配置文件,Log4j 2.x会自动加载该配置,而不会使用classpath中的log4j2.xml配置。这就实现了测试与生产环境的配置分离。
  2. 在测试类上标注@BeforeClass来设置log4j.configurationFile属性的值。
  3. 使用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.
        }
    }

你可能感兴趣的:(log4j2,java,后端)