如果我们将log4j2与slf4j api一起使用,我们可以使用它的所有功能吗?

2022-09-02 05:10:33

我们已经迁移了所有代码以使用slf4 API来使用通用API,但是现在我们正在考虑从log4j 1.x升级到log4j 2.x。如果我们使用slf4j API和log4j2作为实现,我们是否能够使用log4j2的所有功能?


答案 1

Log4j2 API 比 SLF4J API 更丰富,许多 Log4j2 API 功能无法通过 SLF4J 访问。有关详细信息,请参阅下文。

Log4j2 实现的功能(如异步记录器、查找、筛选器、布局和追加器)通过配置进行控制,无论您在应用程序中使用何种日志记录 API,这些功能都可用。

请参阅这个答案,了解为什么编程到Log4j2 API是安全的,这是一个不同但相关的问题的答案。

10 Log4j2 API 功能在 SLF4J 中不可用

(1) 消息 API 允许应用程序记录结构化对象,而不仅仅是文本。在内部,Log4j2 将记录的所有内容转换为消息,并将其公开给 API 为应用程序与下游日志记录组件(筛选器、布局、追加器)进行交互提供了各种可能性。如果您要将自定义组件作为 Log4j2 的插件进行开发,以及当您使用内置组件时,这可能很有用。有关内置示例,请参阅如何使用 StructuredDataMessageRfc5424Layout 进行细粒度控制。

(2) Java 8 lambda 支持允许您懒惰地创建参数或记录消息,而无需显式检查是否启用了请求的日志级别。

// Java-8 style optimization: no need to explicitly check the log level:
// the lambda expression is not evaluated if the TRACE level is not enabled
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());

(3) 将 {}样式参数与 String::format -style 参数混合。{} 样式具有更好的性能,可以与任何参数类型一起使用,但该样式提供了对格式设置的细粒度控制。Log4j2允许您轻松混合这些参数样式。例如:%s %dprintf

logger.debug("Opening connection to {}...", someDataSource);
logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());

(4) CloseableThreadContext 比 SLF4J 中的普通 ThreadContext (MDC) 提供了一些额外的便利:完成后,它会自动删除项目。例如:

// Add to the ThreadContext map for this try block only;
try (final CloseableThreadContext.Instance ctc = CloseableThreadContext
        .put("id", UUID.randomUUID().toString())
        .put("loginId", session.getAttribute("loginId"))) {
    logger.debug("Message 1");
    // call some other code that also does logging 
    ...
    logger.debug("Message 2");
    ...
} // "id" and "loginId" are now removed from the ThreadContext map

(5)Log4j2的ThreadContext除了键值对之外,还具有支持堆栈功能的方法(在Log4j 1中过去称为NDC)。pushpop

(6) SLF4J 不支持致命日志级别。

(7) Log4j2 支持自定义日志级别。这些可以与方法一起使用,例如:,或者您可以为自定义日志级别生成具有方便方法的自定义记录器包装器。loglogger.log(Level.getLevel("FINE"), "... msg")

(8) Log4j2 API 接受任何对象,而不仅仅是字符串。这是允许Log4j2“无垃圾”的原因之一,这意味着它将避免分配新对象。如果对象是数字、字符序列或实现 (Log4j2) StringBuilderFormattable 接口,则会记录对象而不创建任何临时字符串。

Log4j2 API 还将避免在记录 10 个或更少的参数时创建 vararg 数组。SLF4J 在记录超过 2 个参数时会创建 vararg 数组。

(9)以上内容只需直接使用Log4j2 API即可免费获得。最重要的是,如果您真的关心避免创建临时对象(如某些交互式游戏和低延迟金融应用程序所做的那样),则可以避免使用Unbox实用程序类自动装箱基元参数。

(10) SLF4J Markers 使用粗粒度同步可能会对多线程应用程序 (SLF4J-240) 的性能产生影响。请参阅此性能测试结果页的高级筛选部分。


免责声明:我为Log4j2做出贡献。


答案 2

推荐