从 Log4j 1.x 迁移到 2.x
Log4j 1.x 已于 2015 年 达到寿命终结,不再受支持。
本页介绍如何将当前使用 Log4j 1.x API 的应用程序或库迁移到使用 Log4j v2 作为其主要日志框架。
选项 1:使用 Log4j 1.x 桥接 (log4j-1.2-api)
您可以通过将 Log4j 1.x jar 文件替换为 Log4j 2 的 log4j-1.2-api.jar
来将应用程序转换为 Log4j 2,无需任何代码更改。
Log4j 1.x 桥接在以下情况下很有用
- 应用程序本身(可能部分)仍在使用 Log4j 1.x API,或者
- 应用程序依赖于依赖于 Log 1.x API 的库,或者
- 应用程序需要支持旧的 Log4j 1.x 格式的日志配置。
要使用此选项,应用程序需要使用以下三个 jar 文件:Log4j 2 API jar (log4j-api.jar
)、Log4j 2 实现 jar (log4j-core.jar
) 和 Log4j 1.x 桥接 jar (log4j-1.2-api.jar
)。
对于大多数应用程序来说,这已经足够了。这是一种低成本的迁移方式,也可以允许随着时间的推移逐步进行迁移。
启用 Log4j 1.x 桥接
通过以下步骤之一启用 Log4j 1.x 桥接
- 将系统属性“log4j1.compatibility”设置为“true”。Log4j 2 然后会将 log4j.properties、log4j-test.properties、log4j.xml 和 log4j-test.xml 添加到它在类路径上搜索的 配置文件 中。
- 将 Log4j 1 系统属性“log4j.configuration”设置为 log4j 1 配置文件的位置。文件必须具有“.properties”或“.xml”的文件扩展名。
API 兼容性
Log4j 2 通过提供包含这些方法的类的替代实现来支持 Log4j 1 日志方法。这些类可以在与项目一起分发的 log4j-1.2-api jar 中找到。所有执行日志记录的调用都会导致传递到日志记录方法的数据被转发到 Log4j2 API,在那里它们可以由 Log4j 2 API 的实现处理。
配置兼容性
Log4j 2 支持 Log4j 1 配置文件。在 Log4j 1 分发版中提供的附加器、布局和过滤器的配置将被重定向到它们的 Log4j 2 对应物 - 除了实现的重写策略。这意味着虽然这些组件的行为类似,但它们可能并不完全相同。例如,XMLLayout 生成的 XML 可能与 Log4j1XMLLayout 生成的 XML 不完全匹配。
此外,Log4j 2 支持自定义 Log4j 1 附加器、过滤器和布局,但有一些限制。由于原始 Log4j 1 组件可能不存在于 Log4j 2 中,因此扩展它们的自定义组件将失败。
支持的组件
支持的附加器包括:AsyncAppender、ConsoleAppender、DailyRollingFileAppender、FileAppender、NullAppender、RewriteAppender(有限)、RollingFileAppender、SyslogAppender。
支持的过滤器包括:DenyAllFilter、LevelMatchFilter、LevelRangeFilter、StringMatchFilter。
支持的布局包括:HtmlLayout、PatternLayout、SimpleLayout、TTCCLayout、XmlLayout。
支持的重写策略包括:MapRewritePolicy、PropertyRewritePolicy。
不支持或未实现的组件
如果您的配置包含以下任何组件,请考虑 将您的配置迁移 到 Log4j 2 格式。
附加器
- JDBCAppender(无法映射到 Log4j 2 的 JdbcAppender)
- JMSAppender
- SMTPAppender
- SocketAppender(需要使用 SerializedLayout,这是一个安全风险)
- SocketHubAppender(需要使用 SerializedLayout,这是一个安全风险)
- TelnetAppender(安全风险)
重写策略
- ReflectionRewritePolicy
- 自定义重写策略,因为 LoggingEvent 当前是一个空操作。
渲染器
Log4j 2 当前忽略渲染器。
Log4j 1.x 桥接的限制
如果应用程序满足以下要求,则可以通过仅使用桥接而无需进一步的代码更改来迁移
- 它们不得访问 Log4j 1.x 实现内部的方法和类,例如
Appender
、LoggerRepository
或Category
的callAppenders
方法。 - 它们不得以编程方式配置 Log4j。
- 它们不得通过调用 Log4j 1.x 类
DOMConfigurator
或PropertyConfigurator
来配置。
何时停止使用 Log4j 1.x 桥接
一旦您迁移了所有受您控制的应用程序和库代码,您可能不再需要桥接。请注意,当您使用可以配置为使用多个日志框架的库/框架时,您通常也不需要 log4j-1.2-api 桥接,因为您可能能够直接将其配置为使用 Log4j v2 而不是 v1。一些库/框架甚至会自动检测其类路径上是否存在某些日志框架实现,并自动相应地切换其内部日志委托;尝试简单地删除 Log4j v1 依赖项而不是用此桥接替换它,并测试所有依赖项的日志记录是否仍然有效。
如果您拥有或可以为所依赖的库贡献开源代码,请考虑用 v2 API 替换其对 Log4j v1 API 的使用。
虽然 Log4j 1.x 桥接支持使用 Log4j 1.x 属性或 XML 格式的日志配置,但迁移到新的 2.x 格式并不困难。Log4j 2 网站包含有关 2.x 配置格式的广泛文档。以下是一些将日志配置从 v1 格式迁移到 v2 格式的示例。
选项 2:将您的应用程序转换为 Log4j 2 API (log4j-api)
另一个迁移选项涉及更改您的应用程序代码以使用 Log4j 2 API。在大多数情况下,从 Log4j 1.x API 转换为 Log4j 2 应该相当简单。许多日志语句不需要修改。但是,在必要时,必须进行以下更改。
Log4j 1.x | Log4j 2.x |
---|---|
包名:org.apache.log4j |
org.apache.logging.log4j |
调用 org.apache.log4j.Logger.getLogger() |
org.apache.logging.log4j.LogManager.getLogger() |
调用 org.apache.log4j.Logger.getRootLogger() 或 org.apache.log4j.LogManager.getRootLogger() |
org.apache.logging.log4j.LogManager.getRootLogger() |
调用接受 LoggerFactory 的 org.apache.log4j.Logger.getLogger |
移除 org.apache.log4j.spi.LoggerFactory 并使用 Log4j 2 的其他扩展机制之一 |
调用 org.apache.log4j.Logger.getEffectiveLevel() |
org.apache.logging.log4j.Logger.getLevel() |
调用 org.apache.log4j.LogManager.shutdown() |
在版本 2 中不需要,因为 Log4j Core 现在在启动时自动添加 JVM 关闭钩子以执行任何 Core 清理。从 Log4j 2.1 开始,您可以指定自定义 ShutdownCallbackRegistry 来覆盖默认的 JVM 关闭钩子策略。从 Log4j 2.6 开始,您可以使用 org.apache.logging.log4j.LogManager.shutdown() 手动启动关闭。 |
调用 org.apache.log4j.Logger.setLevel() 或类似方法 |
在 API 级别不支持。Log4j 2 实现类中提供了等效的功能,请参见 org.apache.logging.log4j.core.config.Configurator.setLevel() ,但这可能会使应用程序容易受到 Log4j 2 内部更改的影响。 |
字符串连接,例如 logger.info("hi " + userName) |
参数化消息,例如 logger.info("hi {}", userName) |
org.apache.log4j.MDC 和 org.apache.log4j.NDC |
线程上下文 |
将日志记录配置迁移到 Log4j 2 格式
虽然 Log4j 2 配置语法与 Log4j 1.x 的语法不同,但大多数(如果不是全部)相同的功能都可用。
插值
请注意,通过 ${foo}
语法进行的系统属性插值已扩展为允许从许多不同的来源进行属性查找。有关更多详细信息,请参见 查找 文档。例如,使用名为 catalina.base
的系统属性的查找,在 Log4j 1.x 中,语法将是 ${catalina.base}
。在 Log4j 2 中,语法将是 ${sys:catalina.base}
。
布局
Log4j 1.x 具有与 Log4j 2 中的 XmlLayout 不同的 XMLLayout。log4j-1.2-api 模块包含一个 Log4j1XmlLayout
,它以 Log4j 1.x 格式生成输出。
Log4j 1.x SimpleLayout
可以用 PatternLayout “%level - %m%n” 模拟。
Log4j 1.x TTCCLayout
可以用 PatternLayout “%r [%t] %p %c %notEmpty{%ndc }- %m%n” 模拟。
Log4j 1.x 中的 PatternLayout
和 EnhancedPatternLayout
都可以用 Log4j 2 中的 PatternLayout
替换。log4j-1.2-api 模块包含两个模式转换 “%ndc” 和 “%properties”,它们可以用来模拟 Log4j 1.x PatternLayout 中的 “%x” 和 “%X”(Log4j 2 中的 “%x” 和 %X" 格式略有不同)。
以下是 Log4j 1.x 的一些示例配置及其在 Log4j 2 中的对应配置。
示例 1 - 迁移简单的控制台附加程序配置
Log4j 1.x XML 配置
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<category name="org.apache.log4j.xml">
<priority value="info" />
</category>
<Root>
<priority value ="debug" />
<appender-ref ref="STDOUT" />
</Root>
</log4j:configuration>
Log4j 2 XML 配置
<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="org.apache.log4j.xml" level="info"/>
<Root level="debug">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
示例 2 - 迁移简单的文件附加程序、XMLLayout 和 SimpleLayout 配置
Log4j 1.x XML 配置
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="A1" class="org.apache.log4j.FileAppender">
<param name="File" value="A1.log" />
<param name="Append" value="false" />
<layout class="org.apache.log4j.xml.XMLLayout" />
</appender>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.SimpleLayout" />
</appender>
<category name="org.apache.log4j.xml">
<priority value="debug" />
<appender-ref ref="A1" />
</category>
<root>
<priority value ="debug" />
<appender-ref ref="STDOUT" />
</Root>
</log4j:configuration>
Log4j 2 XML 配置
<Configuration>
<Appenders>
<File name="A1" fileName="A1.log" append="false">
<Log4j1XmlLayout />
</File>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%level - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="org.apache.log4j.xml" level="debug">
<AppenderRef ref="A1"/>
</Logger>
<Root level="debug">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
示例 3 - 迁移 SocketAppender 配置
Log4j 1.x XML 配置。Log4j 1.x 中的这个例子具有误导性。SocketAppender 实际上并不使用布局。配置一个将不会有任何效果。
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="A1" class="org.apache.log4j.net.SocketAppender">
<param name="RemoteHost" value="localhost"/>
<param name="Port" value="5000"/>
<param name="LocationInfo" value="true"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%t %-5p %c{2} - %m%n"/>
</layout>
</appender>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<category name="org.apache.log4j.xml">
<priority value="debug"/>
<appender-ref ref="A1"/>
</category>
<root>
<priority value="debug"/>
<appender-ref ref="STDOUT"/>
</Root>
</log4j:configuration>
Log4j 2 XML 配置
<Configuration>
<Appenders>
<Socket name="A1" host="localHost" port="5000">
<PatternLayout pattern="%t %-5p %c{2} - %m%n"/>
</Socket>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="org.apache.log4j.xml" level="debug">
<AppenderRef ref="A1"/>
</Logger>
<Root level="debug">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
示例 4 - 迁移 AsyncAppender 和 TTCCLayout 配置
Log4j 1.x XML 配置使用 AsyncAppender。
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" configDebug="true">
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="TEMP"/>
</appender>
<appender name="TEMP" class="org.apache.log4j.FileAppender">
<param name="File" value="temp"/>
<layout class="org.apache.log4j.TTCCLayout">
<param name="ThreadPrinting" value="true"/>
<param name="CategoryPrefixing" value="true"/>
<param name="ContextPrinting" value="true"/>
</layout>
</appender>
<root>
<priority value="debug"/>
<appender-ref ref="ASYNC"/>
</Root>
</log4j:configuration>
Log4j 2 XML 配置。
<Configuration status="debug">
<Appenders>
<File name="TEMP" fileName="temp">
<PatternLayout pattern="%r [%t] %p %c %notEmpty{%ndc }- %m%n"/>
</File>
<Async name="ASYNC">
<AppenderRef ref="TEMP"/>
</Async>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="ASYNC"/>
</Root>
</Loggers>
</Configuration>
示例 5 - 迁移使用 AsyncAppender 与控制台和文件的配置
Log4j 1.x XML 配置使用 AsyncAppender。
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" configDebug="true">
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="TEMP"/>
<appender-ref ref="CONSOLE"/>
</appender>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<appender name="TEMP" class="org.apache.log4j.FileAppender">
<param name="File" value="temp"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<root>
<priority value="debug"/>
<appender-ref ref="ASYNC"/>
</Root>
</log4j:configuration>
Log4j 2 XML 配置。请注意,Async Appender 应该在它引用的附加程序之后配置。这将允许它正常关闭。
<Configuration status="debug">
<Appenders>
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</Console>
<File name="TEMP" fileName="temp">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</File>
<Async name="ASYNC">
<AppenderRef ref="TEMP"/>
<AppenderRef ref="CONSOLE"/>
</Async>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="ASYNC"/>
</Root>
</Loggers>
</Configuration>