天天看点

log4j2研究之配置文件模块化

模块化作为软件开发领域里的重要思想之一,我们在实际的工作中处处都能看到其身影。本文将尝试将这种思路应用到log4j2的配置文件中。

1. 概述

在软件开发领域,日志总是非常基础且重要的一环。log4j2作为Java领域里日志框架的佼佼者,后发优势使其迅速获得众多开发者的青睐。

XML配置作为log4j2官方的首推配置方式,被绝大多数开发人员所熟知。但XML语言天然的繁琐啰嗦的语法格式,以及具体业务场景下对日志的精密划分,势必导致我们的log4j2.xml 这个配置文件变得非常臃肿、庞大;于是一个改良思路顺理成章地出现了:我们是否可以将这个文件拆分成多个配置文件,最后再将这些配置文件组装成为一个完整的配置?答案当然是肯定的,接下来笔者就介绍实现这种想法的两种思路。

2. XInclude实现

这种实现方式其实和log4j2本身没有太大的关系,这个属于XML自带的一种模块化思路,具体的可以参见笔者在下面给出的链接。这里就不作过多的纠结,具体的实现方式在官方文档里也已经给出了,读者可以自行查阅(相应的官方文档地址笔者在下面也已给出)。

这里还是给出一些笔者在实际运用过程中遇到的一些注意事项:

  1. <xi:include />

    节点的放置位置很重要。对于include节点导入的内容, 有先后顺序之别。
  2. 如果

    <properties>

    想要覆盖 log4j2-xinclude-properties.xml 中定义的属性, 则需要保证

    <properties>

    在先,而在后。
  3. log4j2-xinclude-appenders.xml 中如果用到了 log4j2-xinclude-properties.xml 中配置的属性,则必须 log4j2-xinclude-properties.xml 在先。
  4. 节点之间的覆盖是整体覆盖,例如下面样例中的

    <properties>

    , 属于

    <properties>

    节点覆盖,而不是里面单个

    <property>

    的重复覆盖。而且xinclude文件中定义时,必须是顶级节点(即Appenders/Loggers/Properties等。)
  5. 之前所谈到的覆盖都是 先到者优先,即保留排名在前的配置项。
  6. 样例XML如下:
    <!--主体log4j2.xml配置文件-->
    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="error" xmlns:xi="http://www.w3.org/2001/XInclude">
        <!-- this will override the log pattern defined in the included log4j-properties.xml -->
        <!--这里定义的Properties将覆盖log4j2-xinclude-properties.xml定义的内容, 注意是全部覆盖, 不仅仅是log-pattern属性. 即使log4j2-xinclude-properties.xml中的Properties也许拥有更多的配置项。-->
        <Properties>
            <Property name="log-pattern">jit %d %-5p [%t] %C{1.} - %m%n</Property>
        </Properties>
    
        <xi:include href="log4j2-xinclude-properties.xml" />
        <xi:include href="log4j2-xinclude-appenders.xml" />
    </Configuration>
    
    <!-- log4j2-xinclude-properties.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <Properties>
        <!-- define the log pattern as a property so that it can be overridden -->
        <Property name="log-pattern">%d %-5p [%t] %C{1.} - %m%n</Property>
    </Properties>
               

注意:

  • 这种方式之下,应用所部署的路径中不能包含有中文。

3. Composite Configuration实现

笔者在查找上一种解决方案的过程中,偶然在官网上看到了另外一种实现思路,也就是LOG4J2中论述的

Composite Configuration

(这里也可以看出LOG4J2的后发优势真是相当巨大,开发人员吸取了大量之前LOG框架的教训并将之在log4j2中进行了解决)。

官方文档里并没有给出相应的示例,笔者结合官方给出的文档,再经过一番源码追踪后,大致实现了一个可运行的版本。

  1. 首先你需要配置一个名为

    log4j.configurationFile

    的配置项(关于这个配置项,你可以在

    ConfigurationFactory

    类中找到),该配置项将指定log4j2的配置文件所在位置。注意这个配置项是可以指定多个配置文件的,你需要做的只是使用逗号将它们分开(注意这个逗号目前是写死在代码里的,具体位置是

    ConfigurationFactory.Factory

    类的

    getConfiguration(LoggerContext, String, URI)

    方法中)。
  2. 第一步提到的配置项,你需要将其放到classpath下新建的

    log4j2.component.properties

    文件中(该文件名是在

    PropertiesUtil

    类中定义的)。
  3. 第二步有一个替换操作,就是将

    log4j.configurationFile

    的配置项注册到系统属性中。
  4. 以上三步的逻辑主要涉及到

    ConfigurationFactory.Factory.getConfiguration()

    PropertiesUtil.getProperties().getStringProperty()

    。读者可自行阅读相应的源码来做到成竹于胸。
  5. 最后给出一个配置示例:
    # 定义在classpath下的 log4j2.component.properties 文件
    log4j.configurationFile=log4j2-test.xml,log4j2-test2.xml
               
  6. 关于配置之间的属性覆盖问题以及其他实现细节,可以参见官方文档说明,笔者就不重复了。

注意:

  • 这种方式之下,每个配置文件必须满足log4j2.xml的格式,例如XML情况下要以

    <Configuration>

    为根节点。

4. Links

  1. XML Inclusions (XInclude)
  2. StackOverflow - log4j2 - include
  3. log4j2-XInlcude官方文档
  4. 自定义Log4j2配置文件位置

继续阅读