API 分离
在选择日志库时,必须注意确保正确考虑多个不同的日志库。例如,您依赖的库代码可能使用 slf4j,而其他库可能只使用 java.util.logging。所有这些都可以路由到 log4j 核心以进行记录。
但是,如果您想使用不同的日志实现(例如 logback),则可以将来自 Log4j API 的消息路由到 logback,确保您的应用程序不绑定到特定的日志框架。
使用 Log4j2 API 的典型类如下所示
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Test {
private static final Logger logger = LogManager.getLogger();
public Log4j2Test(){
logger.info( "Hello World!" );
}
}
为了使用 Log4j2 的 API 部分,我们只需要提供一个依赖项,log4j-api。使用 Maven,您将在依赖项中添加以下内容
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.0</version>
</dependency>
使用 Log4j2 API 和核心
一起使用 Log4j2 API 和实现(核心)意味着日志消息将通过 Log4j2 核心路由。Log4j2 核心实现负责以下内容(注意:这不是一个详尽的列表)
- 系统的配置(例如通过 XML 文件)
- 将消息路由到追加器
- 打开文件和其他资源以进行日志记录(例如网络套接字)
手册中的 配置 页面描述了 Log4j2 核心实现支持的配置格式。
要同时使用 API 和核心实现,您将在依赖项中添加以下内容(假设您使用的是 Maven)
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
</dependency>
请注意,在您的类路径上拥有两个不同版本的 log4j-api 和 log4j-core 并不保证能够正常工作(例如,log4j-api 版本 2.15 和 log4j-core 版本 2.17 并不保证能够正常协同工作)。
使用 Log4j2 API 与 Logback
由于 Log4j2 API 是通用的,因此我们可以使用它通过 SLF4J 发送消息,然后让 Logback 完成消息的实际记录。这意味着您可以编写绑定到 Log4j2 API 的代码,但如果您已经使用 Logback,您的代码的用户不需要使用 Log4j2 核心。
要切换到使用 Logback 作为您的日志后端,您需要在依赖项中添加以下内容(假设您使用的是 Maven)
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
</dependency>
使用 Log4j2 作为 SLF4J 实现
如果您不想依赖 Log4j2 API,而是想使用 SLF4J,这也是可能的。假设我们的代码如下所示
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Log4j2Test {
private static final Logger logger = LoggerFactory.getLogger(Log4j2Test.class);
public Log4j2Test(){
logger.info( "Hello World!" );
}
}
然后我们可以使用 log4j-slf4j-impl 将消息路由到 Log4j2,如下所示
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
</dependency>
请注意,如果我们使用的是 SLF4J 1.8 而不是 1.7,则需要使用 log4j-slf4j18-impl 而不是 log4j-slf4j-impl。
使用 Log4j2 与 JUL
还可以将使用 java.util.logging 记录的消息路由到 Log4j2。假设代码如下所示
import java.util.logging.Logger;
public class Log4j2Test {
private static final Logger logger = Logger.getLogger(Log4j2Test.class.getName());
public Log4j2Test() {
logger.info("Hello World!");
}
}
然后我们还可以通过添加 JUL 桥接并将 -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
设置在 JVM 上来将这些消息路由到 Log4j2 核心(有关此工作原理的更多信息,请参阅 JUL 适配器 上的文档)。
为了将这些消息路由到 Log4j2,您的依赖项将如下所示
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
</dependency>
使用 Log4j2 作为 Log4j1 的后端
某些软件可能仍然依赖 Log4j1,在某些情况下,修改此软件以将其迁移到 Log4j2 可能不可行。
但是,可能无需修改应用程序即可开始使用 Log4j2。
假设我们的代码如下所示
import org.apache.log4j.Logger;
public class Log4j2Test {
private static final Logger logger = Logger.getLogger(Log4j2Test.class);
public Log4j2Test(){
logger.info( "Hello World!" );
}
}
然后我们可以通过依赖 log4j-1.2-api
桥接来快速轻松地配置这些消息以使用 Log4j2 作为日志实现,如下所示
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
</dependency>
这方面有一些限制,但预计它将在大多数常见情况下有效。有关此功能的更多信息,请参阅 迁移手册页面。
结论
借助 Log4j2 提供的 API 分离,可以在同一个项目中使用多个日志 API 和实现。这提供了更大的灵活性,确保您不会绑定到单个 API 或实现。