简体   繁体   English

将 slf4j 与 log4j2 一起使用是否值得

[英]Is it worth to use slf4j with log4j2

I am not able to decide whether to use slf4j or not with log4j2.我无法决定是否将 slf4j 与 log4j2 一起使用。 Based on online posts, does not look like it will have any performance hit but is it really required.根据在线帖子,它看起来不会对性能造成任何影响,但它真的是必需的。

Also these points rule in favor of log4j2:这些点也有利于 log4j2:

  • SLF4J forces your application to log Strings. SLF4J 强制您的应用程序记录字符串。 The Log4j 2 API supports logging any CharSequence if you want to log text, but also supports logging any Object as is.如果您想记录文本,Log4j 2 API 支持记录任何 CharSequence,但也支持按原样记录任何对象。
  • The Log4j 2 API offers support for logging Message objects, Java 8 lambda expressions and garbage-free logging (it avoids creating vararg arrays and avoids creating Strings when logging CharSequence objects). Log4j 2 API 支持记录 Message 对象、Java 8 lambda 表达式和无垃圾记录(它避免在记录 CharSequence 对象时创建可变参数数组并避免创建字符串)。

Go ahead: program to the log4j2 API instead of slf4j继续:编程到 log4j2 API 而不是 slf4j

It's safe: the Log4j2 API offers the exact same guarantees as slf4j - and more.它是安全的:Log4j2 API 提供与 slf4j 完全相同的保证 - 等等。

Now that Log4j2 itself is separated into an API and an implementation module, there is no longer any value in using SLF4J.现在Log4j2本身已经被分成了一个API和一个实现模块,使用SLF4J已经没有任何价值了。

Yes, it is good engineering practice to keep your options open.是的,让您的选择保持开放是一种很好的工程实践。 You may want to change to another logging implementation later.您可能希望稍后更改为另一个日志记录实现。

For the last 10 years or so, building such flexibility in your application meant using a wrapper API like SLF4J.在过去 10 年左右的时间里,在您的应用程序中构建这种灵活性意味着使用像 SLF4J 这样的包装器 API。 This flexibility doesn't come for free though: the disadvantage of this approach is that your application cannot use the richer feature set of the underlying logging library.但是,这种灵活性并不是免费的:这种方法的缺点是您的应用程序无法使用底层日志库的更丰富的功能集。

Log4j2 offers a solution that doesn't require that your application is restricted to the lowest common denominator. Log4j2 提供了一种解决方案,它不需要将您的应用程序限制为最小公分母。

The escape valve: log4j-to-slf4j逃生阀:log4j-to-slf4j

Log4j2 includes a log4j-to-slf4j bridge module. Log4j2 包含一个log4j-to-slf4j桥接模块。 Any application coded against the Log4j2 API can choose to switch the backing implementation to any slf4j-compliant implementation at any time.任何针对 Log4j2 API 编码的应用程序都可以随时选择将支持实现切换到任何符合 slf4j 的实现。

log4j 到 slf4j

As mentioned in the question, using the Log4j2 API directly offers more functionality and has some non-functional advantages versus using a wrapper API like slf4j:正如问题中所提到的,与使用像 slf4j 这样的包装器 API 相比,直接使用 Log4j2 API 可以提供更多功能并且具有一些非功能性优势:

  • Message API消息接口
  • Lambdas for lazy logging用于延迟日志记录的 Lambda
  • Log any Object instead of just Strings记录任何对象而不仅仅是字符串
  • Garbage-free: avoid creating varargs or creating Strings where possible无垃圾:尽可能避免创建可变参数或创建字符串
  • CloseableThreadContext automatically removes items from the MDC when you're finished with them CloseableThreadContext 在您完成项目后自动从 MDC 中删除项目

(See 10 Log4j2 API features not available in SLF4J for more details.) (有关更多详细信息,请参阅SLF4J 中不可用的 10 个 Log4j2 API 功能。)

Applications can safely use these rich features of the Log4j2 API without being locked in to the native Log4j2 core implementation.应用程序可以安全地使用 Log4j2 API 的这些丰富功能,而不会被锁定到本机 Log4j2 核心实现。

SLF4J is still your safety valve, it just doesn't mean your application should code against the SLF4J API anymore. SLF4J 仍然是您的安全阀,但这并不意味着您的应用程序应该再针对 SLF4J API 进行编码。


Disclosure: I contribute to Log4j2.披露:我为 Log4j2 做出了贡献。


Update: There seems to be some confusion that programming to the Log4j2 API somehow introduces a "facade for a facade".更新:似乎有些混乱,对 Log4j2 API 编程以某种方式引入了“外观的外观”。 There is no difference in this respect between the Log4j2 API and SLF4J. Log4j2 API 和 SLF4J 在这方面没有区别。

Both APIs require 2 dependencies when using a native implementation, and 4 dependencies for a non-native implementation.使用本机实现时,这两个 API 都需要 2 个依赖项,非本机实现需要 4 个依赖项。 SLF4J and the Log4j2 API are identical in this respect. SLF4J 和 Log4j2 API 在这方面是相同的。 For example:例如:

SLF4J 和 Log4j 2 API 所需的依赖项类似

There are quite a few considerations which make logging "more complicated than it seems at first glance", (hence the multi-decade of bitter in-fighting!).有很多考虑因素使日志记录“比乍一看更复杂”,(因此是数十年的苦战!)。

Separation of Concerns关注点分离

At the end of the day, code 'sends log data' and that data 'ends up somewhere'.在一天结束时,代码“发送日志数据”并且该数据“最终到达某处”。 But where it ends up depends on the purpose for which it is being gathered.但它的最终位置取决于收集它的目的。 Greatly complicating the picture is the fact that modern software is composed of various components, and they all potentially have a need to log.使情况大大复杂化的是,现代软件由各种组件组成,而且它们都可能需要记录日志。

Let's consider a worst-case: all components use System.out#println(String) .让我们考虑一个最坏的情况:所有组件都使用System.out#println(String) At least all the statements are in execution-order, but it might not be simple to discern which component generated each piece of output.至少所有语句都是按执行顺序排列的,但要辨别哪个组件生成了每条输出可能并不容易。 And some components might be overly verbose for the context in which they are used.对于使用它们的上下文,某些组件可能过于冗长。

Let's consider a next-worst-case: all components make their own arrangements for controlling their logging behaviour and destination.让我们考虑下一个最坏的情况:所有组件都做出自己的安排来控制它们的日志记录行为和目的地。 The admin might have to configure dozens of log systems for a single piece of software.管理员可能必须为单个软件配置数十个日志系统。 Now the log statements are not together and they're out of order.现在日志语句不在一起并且它们乱序。 Hopefully they all have a consistent timestamp strategy!希望他们都有一致的时间戳策略!

We would like something in-between: something whereby code can say 'log this' and an admin can control where it ends up.我们想要介于两者之间的东西:代码可以说“记录这个”并且管理员可以控制它结束的地方。

An overly brief history过于简短的历史

Enter Log4J v1, which tackled the problem with notions of 'levels', 'appenders', 'filters' 'layouts' and 'contexts' ... a conceptual architecture supported by a hierarchical 'logger namespace' (including a way to naturally leverage off Java package namespaces), plus a configuration mechanism for easy management.进入 Log4J v1,它解决了“级别”、“附加程序”、“过滤器”、“布局”和“上下文”等概念的问题……一个由分层“记录器命名空间”支持的概念架构(包括一种自然利用关闭 Java 包命名空间),以及便于管理的配置机制。

That was all fine and good ... so long as all the components in the software relied on the same version!这一切都很好……只要软件中的所有组件都依赖于相同的版本! There was a time when these things were in flux.曾经有一段时间,这些事情都在不断变化。 The main contribution of SLF4J was to 'harden' these concepts into a stable API from the point of view of the component-developer, without prejudicing the options of the admin for doing their part of the work.从组件开发人员的角度来看,SLF4J 的主要贡献是将这些概念“强化”为稳定的 API,而不影响管理员完成他们部分工作的选项。 Libraries could rely on the SLF4J 'facade', expecting that they'd be talking to the 'implementation' just a few calls down the stack.图书馆可以依赖 SLF4J 'facade',期望他们只在堆栈中调用几次就可以与“实现”交谈。 Administrators could choose what suited them to compose the logs into a coherent record they cared about.管理员可以选择适合他们的方式将日志组合成他们关心的连贯记录。

(It is even more complicated when your software runs in a container, and the container has its own logging needs, and you're not even the same app running in the container ... Tomcat's JULI logging - used for its own internal logging - 'gets out of the way' of apps running in classloader sub-contexts.) (当您的软件在容器中运行时,情况就更加复杂了,并且容器有自己的日志记录需求,而您甚至不是在容器中运行的同一个应用程序......Tomcat 的 JULI 日志记录 - 用于它自己的内部日志记录 -在类加载器子上下文中运行的应用程序“不碍事”。)

Mysteriously scorning the work by Log4J, the Java Community Process decided to implement much-the-same conceptual architecture in java.util.logging , with arguably less flexibility in the details. Java Community Process 神秘地蔑视 Log4J 的工作,决定在java.util.logging实现几乎相同的概念架构,但在细节上的灵活性可能会降低。 However, with jul being essentially a sub-set of the semantic richness of SLF4J, it was easy make SLF4J a facade to jul .然而,由于jul本质上是 SLF4J 语义丰富性的一个子集,所以很容易让 SLF4J 成为jul的门面。

Apache's Commons Util Logging was probably not very necessary. Apache 的 Commons Util Logging 可能不是很有必要。 Ceki's own Logback introduced management features which Log4J v1 did not have at the time - not least being an implementation of SLF4J and solving all those very-real classloader headaches, but also providing a competent implementation with some appealing features for the administrator. Ceki 自己的 Logback 引入了当时 Log4J v1 没有的管理功能——不仅是 SLF4J 的实现并解决了所有那些非常真实的类加载器难题,而且还为管理员提供了具有一些吸引人的功能的称职实现。

Logging for different situations不同情况下的日志

But logging is done in a lot of different contexts.但是日志记录是在许多不同的上下文中完成的。 Whacking those messages out to super-slow I/O without unduly blocking the thread, and not paying the price of computing the log message unless it's needed, and producing coherent logs in multi-threaded contexts ... these things all matter.在不过度阻塞线程的情况下将这些消息重击到超慢 I/O,并且除非需要,否则不支付计算日志消息的代价,并在多线程上下文中生成连贯的日志......这些都很重要。 (Which is why java.util.logging is not often used!). (这就是为什么不经常使用java.util.logging原因!)。

Sometimes, the required optimisations will impact on the conceptual architecture, which in turn must impact on the developer-side API.有时,所需的优化会影响概念架构,而这反过来又会影响开发人员端 API。 For example, the opportunities presented by closures will definitely speed things up if the log message ends up being a no-op because of filtering.例如,如果日志消息由于过滤而最终成为无操作,则闭包提供的机会肯定会加快速度。 Either a SLF4J.next or some other API needs to be considered to make use of that feature, and Log4J2 need not be excluded from this decision.需要考虑 SLF4J.next 或其他一些 API 来使用该功能,并且不需要将 Log4J2 排除在此决定之外。 With the API portion being a conceptual super-set of that offered by SLF4J, it is simple to make it a facade either for SLF4J and those implementations under it ... or more direct bridges to what the administrator has preferred.由于 API 部分是 SLF4J 提供的概念超集,因此很容易使它成为 SLF4J 及其下的那些实现的外观……或者更直接地连接到管理员喜欢的东西。

For the app-developer, it really doesn't matter, so long as ultimately, there is one logging facility chosen by the administrator, and all the components can get a log out to it.对于应用程序开发人员来说,这真的无关紧要,只要最终管理员选择了一个日志记录工具,并且所有组件都可以从中注销。 If the facility can accept messages via SLF4J and Log4J2-the-API, then that's great .如果该工具可以通过 SLF4JLog4J2-the-API 接受消息,那就太好了 Log4J2-the-implementation does just this. Log4J2-the-implementation 就是这样做的。 You can have your cake and eat it too: your application can enjoy the opportunities offered by Log4J2-the-API while still using libraries that are adequately catered-for by SLF4J.您也可以拥有自己的蛋糕,也可以吃它:您的应用程序可以享受 Log4J2-the-API 提供的机会,同时仍然使用 SLF4J 充分满足的库。 If the administrator scorns Log4J2-the-implementation (though it is hard to see why they would, from any angle), then they can use anything that already supports SLF4J without waiting for that logging implementation to support Log4J2-the-API.如果管理员蔑视 Log4J2-the-implementation(尽管从任何角度都很难看出他们为什么会这样做),那么他们可以使用任何已经支持 SLF4J 的东西,而无需等待日志实现来支持 Log4J2-the-API。 You can have your cake and eat it.你可以吃你的蛋糕。

For library developers , it is more of an issue.对于库开发人员来说,这更像是一个问题。 The safe path is SLF4J because of its widespread adoption.安全路径是 SLF4J,因为它被广泛采用。 If logging is critical to the success of your library ... particularly if it is multi-threaded, log statements are potentially expensive to produce, and it might be better to omit the processing if they will not ultimately be consumed, if there is a large volume of log statements to handle, performance is critical, and your users are likely to appreciate the benefits of Log4J2-the-implementation, then do Log4J2.如果日志记录对您的库的成功至关重要……特别是如果它是多线程的,则日志语句的生成可能会很昂贵,如果它们最终不会被消耗,则最好省略处理,如果有要处理大量日志语句,性能至关重要,并且您的用户可能会欣赏 Log4J2-实现的好处,然后执行 Log4J2。 But you're not stealing opportunities from your users by remaining with SLF4J, either.但是您也不会因为继续使用 SLF4J 而从您的用户那里窃取机会。 The admin can still use Log4J-the-implmenation if they wish.如果愿意,管理员仍然可以使用 Log4J-the-implementation。

The bottom line底线

If you want the features afforded by Log4J2 then go for them.如果您想要 Log4J2 提供的功能,请选择它们。 If you don't need them, SLF4J is a mature, stable interface with a lot of support.如果你不需要它们,SLF4J 是一个成熟、稳定的接口,有很多支持。 SLF4J remains an important piece of the open-source infrastructure. SLF4J 仍然是开源基础设施的重要组成部分。 Ceki has done the community a great service, for a lot of griping in return. Ceki 为社区提供了很好的服务,作为回报,很多抱怨。

But rich APIs supported by competent implementations prevail in the end.但最终还是由有能力的实现支持的丰富的 API 盛行。 Today's stability is tomorrows stagnation.今天的稳定就是明天的停滞。 The process of refinement keeps going.细化的过程一直在进行。 No need to get off the bus so long as it is going where you want to go.不需要下车,只要它去你想去的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM