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 发行版中提供的 Appenders、Layouts 和 Filters 的配置将被重定向到它们的 Log4j 2 对应物 – 已实施的重写策略除外。 这意味着尽管这些组件的行为相似,但它们可能并不完全相同。 例如,XMLLayout 生成的 XML 可能与 Log4j1XMLLayout 生成的 XML 不完全匹配。
此外,Log4j 2 支持带有一些约束的自定义 Log4j 1 Appenders、Filters 和 Layouts。 由于 Log4j 2 中可能不存在原始 Log4j 1 组件,因此扩展它们的自定义组件将失败。
支持的组件
支持的 Appender 包括:AsyncAppender、ConsoleAppender、DailyRollingFileAppender、FileAppender、NullAppender、RewriteAppender(受限)、RollingFileAppender、SyslogAppender。
支持的过滤器包括:DenyAllFilter、LevelMatchFilter、LevelRangeFilter、StringMatchFilter。
支持的布局包括:HtmlLayout、PatternLayout、SimpleLayout、TTCCLayout、XmlLayout。
支持的重写策略包括:MapRewritePolicy、PropertyRewritePolicy。
不支持或未实现的组件
如果您的配置包含以下任何组件,请考虑将您的配置迁移到 Log4j 2 格式。
Appenders
JDBCAppender(不能映射到 Log4j 2 的 JdbcAppender)
JMSAppender
SMTPAppender
SocketAppender(需要使用有安全风险的 SerializedLayout)
SocketHubAppender(需要使用 SerializedLayout,这是一个安全风险)
TelnetAppender(安全风险)
重写策略
反射重写策略
自定义重写策略,因为 LoggingEvent 目前是无操作的。
渲染器
Log4j 2 当前忽略渲染器。
Log4j 1.x 桥接器的限制
如果应用程序满足以下要求,则可以仅使用桥接器进行迁移,而无需进一步更改代码:
- 他们不得访问 Log4j 1.x 实现内部的方法和类,例如 Appenders、LoggerRepository 或 Category 的 callAppenders 方法。
- 他们不得以编程方式配置 Log4j。
- 它们不得通过调用 Log4j 1.x 类 DOMConfigurator 或 PropertyConfigurator 进行配置。
何时停止使用 Log4j 1.x 桥接器
一旦您将所有自己的应用程序和库代码迁移到您的控制之下,您可能就不再需要这座桥了。 请注意,当您使用可以配置为使用多个日志记录框架的库/框架时,您通常也不需要 log4j-1.2-api 桥,因为您可以直接将其配置为使用 Log4j v2 而不是 v1 . 一些库/框架甚至会自动检测其类路径中某些日志框架实现的存在,并相应地自动切换其内部日志委托; 尝试简单地删除 Log4j v1 依赖项,而不是用此桥替换它,并测试所有依赖项的日志记录是否仍然有效。
如果您拥有或可以为您所依赖的库贡献开源代码,请考虑将其对 Log4j v1 API 的使用替换为 v2 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 |
---|---|
Package name: org.apache.log4j | org.apache.logging.log4j |
Calls to org.apache.log4j.Logger.getLogger() | org.apache.logging.log4j.LogManager.getLogger() |
Calls to org.apache.log4j.Logger.getRootLogger() or org.apache.log4j.LogManager.getRootLogger() | org.apache.logging.log4j.LogManager.getRootLogger() |
Calls to org.apache.log4j.Logger.getLogger that accept a LoggerFactory | Remove the org.apache.log4j.spi.LoggerFactory and use one of Log4j 2’s other extension mechanisms |
Calls to org.apache.log4j.Logger.getEffectiveLevel() | org.apache.logging.log4j.Logger.getLevel() |
Calls to org.apache.log4j.LogManager.shutdown() | Not needed in version 2 because the Log4j Core now automatically adds a JVM shutdown hook on start up to perform any Core clean ups. Starting in Log4j 2.1, you can specify a custom ShutdownCallbackRegistry to override the default JVM shutdown hook strategy. Starting in Log4j 2.6, you can use org.apache.logging.log4j.LogManager.shutdown() to initiate shutdown manually. |
Calls to org.apache.log4j.Logger.setLevel() or similar methods | Not supported at API level. Equivalent functionality is provided in the Log4j 2 implementation classes, see org.apache.logging.log4j.core.config.Configurator.setLevel(), but this may leave the application susceptible to changes in Log4j 2 internals. |
String concatenation like logger.info("hi " userName) | Parameterized messages like logger.info("hi {}", userName) |
org.apache.log4j.MDC and org.apache.log4j.NDC | Thread Context |
将日志记录配置迁移到 Log4j 2 格式
尽管 Log4j 2 配置语法与 Log4j 1.x 不同,但大多数(如果不是全部)相同的功能是可用的。
插值
请注意,通过 {foo} 语法的系统属性插值已扩展为允许从许多不同来源查找属性。 有关更多详细信息,请参阅查找文档。 例如,使用名为 catalina.base 的系统属性查找,在 Log4j 1.x 中,语法为 {catalina.base}。 在 Log4j 2 中,语法为
Layouts
Log4j 1.x 有一个 XMLLayout,它不同于 Log4j 2 中的 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”,可用于模拟“%x”和“ Log4j 1.x PatternLayout 中的“%X”(Log4j 2 中的“%x”和 %X“格式略有不同)。
以下是 Log4j 1.x 及其在 Log4j 2 中的对应配置的一些示例配置。
示例 1 – 迁移简单的 Console Appender 配置
Log4j 1.x XML 配置
代码语言:javascript复制<!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 配置
代码语言:javascript复制<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 – 迁移一个简单的 File Appender、XMLLayout 和 SimpleLayout 配置
Log4j 1.x XML 配置
代码语言:javascript复制<!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配置
代码语言:javascript复制<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 实际上并不使用 Layout。 配置一个将没有效果。
代码语言:javascript复制<!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配置
代码语言:javascript复制<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。
代码语言:javascript复制<!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配置
代码语言:javascript复制<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。
代码语言:javascript复制<!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 配置。 请注意,应该在它引用的 appender 之后配置 Async Appender。 这将允许它正确关闭。
代码语言:javascript复制<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>
本文为从大数据到人工智能博主「xiaozhch5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://cloud.tencent.com/developer/article/2024094