Java中的日志到底是什么意思?

118

为什么会使用以下的某个包而不是其他的呢?

  • Java Logging(Java日志)
  • Commons Logging(通用日志)
  • Log4j
  • SLF4j
  • Logback

4
你可能想要查看 https://dev59.com/wHNA5IYBdhLWcg3wrPyq,该网页比较了 SLF4j 和 Commons Logging。 - James McMahon
25
为什么Ceki要创建三个日志框架!!!那简直疯了…… - mP.
6
@mP. - log4j是最早的,然后出现了争议,于是有了slf4j+logback。slf4j是API,而logback则是API的实现。不管其他方面如何,slf4j非常有用。 - Thorbjørn Ravn Andersen
3
有关Ceki Gülcü为什么创建SLF4J+Logback的详细信息,请参见以下Devoxx演讲:http://www.parleys.com/#st=5&id=1701 - Alex Bitek
这次最好的成果是 slf4j API,希望能够统一日志记录领域。我认为 logback 还没有在开发者中达到关键质量。 - Thorbjørn Ravn Andersen
8个回答

89

按api出现的时间顺序(就我所知):

  • Log4j因为大多数人都在使用它(根据我的经验)
  • Commons Logging因为开源项目使用它(这样它们可以与集成解决方案中使用的任何日志记录框架集成);如果您是API/Framework/OSS并且依赖于使用Commons Logging的其他包,则尤其有效。
  • Commons Logging,因为您不希望“锁定”到特定的日志记录框架(因此您会改为锁定到Commons Logging提供给您的内容)-我认为没有理由以这个点作为决定使用的原因。
  • Java logging因为您不想添加额外的jar。
  • SLF4j因为它比Commons Logging更新,并提供参数化日志记录:

logger.debug("The entry is {}.", entry);
//which expands effectively to
if (logger.isDebugEnabled()){
    // Note that it's actually *more* efficient than this - see Huxi's comment below...
    logger.debug("The entry is " + entry + "."); 
}
  • 选择Logback,因为它比log4j更新,并且支持参数化日志记录,因为它直接实现了SLF4j
  • 选择SLF4j/Logback,因为它是由曾经编写过log4j的同一位作者所写,所以他让它更加完善(感谢Ken G在此处的发言。看到他们早期的新闻发布时,这个说法似乎是正确的)
  • 选择SLF4j,因为他们还发布了一个log4j适配器,所以您不必在旧代码中“切换”log4j - 只需使log4j.properties使用SLF4j并进行配置即可。

3
据我所知,commons logging 的思想是应该在库中使用。这样一来,库就可以始终使用与托管应用程序相同的日志记录框架(通过 commons logging)。 - Joachim Sauer
感谢Loki提出的问题。现在我知道我不会再使用log4j作为我的默认框架了。SLF4j FTW!同时也感谢Ken G指出SLF4j是由与log4j同一位开发者编写的。 - Stephen
3
你代码示例中的注释并不完全正确。实际上,消息格式化是由Logback懒加载执行的,只有在事件被一个appender真正处理且该appender需要格式化的消息时才会发生——比如对于SocketAppender就不会发生这种情况,因为事件是使用未更改的消息模式 + 参数作为字符串进行序列化的。不过,我猜这取决于你如何定义“有效”。它肯定会发出相同的消息(至少如果entry和object是相同的),所以请原谅我的吹毛求疵。 - Huxi
6
SLF4J实际上只是一个坐在其他日志框架之上的API。与Commons Logging的目标类似,但从我的经验来看更加直观易懂。 - James McMahon

38
我觉得在Java中记录日志非常困惑、不一致、文档质量差,尤其是很混乱。此外,这些日志记录框架之间存在巨大的相似性,导致工作重复,同时会让你对当前实际所处的日志记录环境感到困惑(例如hibernate可能使用log4j,而tomcat则使用java.util.logging)。Apache commons旨在桥接不同的日志记录框架,但实际上只增加了更多的复杂性。如果没有提前知道这一点,那么就会让人无从下手。为什么我的日志消息没有打印到控制台等等?哦,因为我正在查看Tomcat日志,不是log4j。最后,所有这些日志记录框架都过于复杂。在Java中进行记录日志的方式一直是一个杂乱无章的局面,让像我这样的开发人员感到沮丧和困惑。
早期版本的Java没有内置的日志记录框架,这就导致了这种情况。

19
这是一个回答吗?看起来更像是一通牢骚。 - Michael Myers
15
抱歉,这有点发牢骚。但它也是对“Java中的日志记录有什么问题?”的一个有力回应。简而言之,答案是它非常有缺陷。 - Julien Chastang
1
这并不值得一个负一票;P 但是值得思考。 - guyumu
21
问题始于Sun将java.util.logging添加到Java 1.4时。在此之前,LOG4J已经被广泛使用。之后,就需要编写包装器来支持LOG4J和java.util.logging。同时,由于jul包含在java.*包中,无法通过交换JAR文件来替换它,这是SLF4J桥接其他框架的方式。这可能是Sun最糟糕的想法...最终导致了错误的假设,即“良好的Java开发者”应该使用jul。 - Huxi
4
@Huxi,我认为日历API更糟糕。为了维护Sun的声誉,需要说明这并不是他们自己编写的代码,而是来自于Taglient。 - Thorbjørn Ravn Andersen

22

之前没有提到的一个重要点是:

SLF4J(以及作为日志后端的Logback和LOG4J)支持所谓的映射诊断上下文(Mapped Diagnostic Context,MDC,请参见JavaDoc文档)。

这实际上是一个线程本地的Map<String,String>,您可以使用它向日志事件添加其他上下文信息。 MDC的当前状态将附加到每个事件中。

如果您将用户名和请求的URL(在Web应用程序的情况下)等内容放入其中,则这可以非常有用。例如,这可以通过过滤器自动完成。


2
从技术上讲,它是一个线程本地的Map<String,String>。 - pdxleif

17

请参考对问题“记录错误的最佳实践是什么?”的答案,特别是:

  • 使用Commons Logging可能会存在一些潜在的类加载问题。

  • Log4J和SLF4J是由同一个人开发的,通过在Log4J中发现的问题进行学习。


4
在我们公司的项目中,我们使用LOG4j,就像Stephen在他的示例中展示的那样,它非常易于使用。我们还编写了自己的模式类用于LOG4j,因此您可以创建自己的输出文件模式。您可以描述日志文件的外观。可以增强原始的log4j类。
您可以在log4j.properties文件中更改所有LOG4j属性,因此您可以为不同的项目使用不同的文件。
Java日志记录不是我喜欢的东西,但这可能是因为我从一开始就使用log4j。

4

Commons Logging概述解释了它存在的原因:在您无法控制底层日志框架的库代码中进行记录非常重要,这对于各种Apache项目非常重要,这些项目将链接到外部应用程序。但是,在您完全控制的内部IT项目中可能并不那么重要。

话虽如此,我和我认识的许多其他开发人员都会写入Commons Logging。原因是为了最小化心理负担:您可以更改项目或工作,而无需学习新的框架(前提是新的工作/项目也使用CL,并且/或者您可以说服他们转换到它)。

此外,围绕您使用的任何框架创建自己的包装器也有一定的价值。正如此处所描述的那样,我喜欢使用LogWrapper对象来提供自定义字符串化(重要),并最小化日志记录语句的视觉杂乱程度(不太重要)。


1
还有一个 commons.logging=>SLF4J 桥接器,可以用于将所有的 CL 日志路由到 SLF4J。SLF4J 支持桥接 commons.logging、LOG4J 和(有点麻烦,但尽可能好)java.util.logging,因此所有日志都将最终进入您使用的任何 SLF4J 后端。请参见 http://slf4j.org/legacy.html 我会使用 Logback,顺便说一下,但你可以说我有偏见。 - Huxi

2

通常情况下,我会默认使用Log4J。

如果我不介意依赖于Java 1.4,我会使用Java Logging,但我仍然更喜欢使用Log4J。

如果我正在增强已经使用Commons Logging的东西,我会继续使用它。


不介意依赖于1.4吗?即使1.4已经到达了其服务寿命的尽头。 - Tom Hawtin - tackline
2
@Tom 他的意思是jdk1.4或更高版本,别傻了。 - mP.
实际上,最近我在一个仍在运行jdk 1.3下的系统中工作 :-(,而且不到两年前我还在维护一个jdk 1.2系统。太多地方除非必须升级,否则他们就拒绝安装升级。 - Michael Rutherfurd

0
我建议创建一个轻量级的日志门面,可以写入任何日志框架,这时选择支持引擎几乎就变得无关紧要了。

2
这就是commons logging的作用,何必重复造轮子呢?而且你的外观模式还要处理一些commons logging已经解决了的问题。 - James A. N. Stauffer
这种方法在许多情况下都是有效的,特别是当您的代码必须在任意平台上运行时。与 Eclipse 等应用程序服务器相比,底层日志记录 API 往往不同。 - McDowell
1
最近我们将框架移植到了紧凑框架(.Net)中,这个方法帮了我大忙。如果我们在nLog上硬编码依赖关系,那就惨了。因为我们采用了这种方法,我们能够轻松地使用空记录器并保持愉快。请有人给我点赞回到0吧 :-) - tsimon
3
已经有这样一个东西了,可以看看slf4j。它是一个被广泛接受的轻量级封装器,允许你通过在运行时classpath上切换jar包来在应用程序启动时切换日志框架。 - deterb
1
日志记录有自己发现使用哪个框架的方式 - 这并不好,而且相当复杂。Ceki 创建了多少个日志记录框架?即使是使用自己的日志记录,也应该始终努力将一个层次的互动和实现隐藏起来。在幕后,您可以像Travis所提到的那样插入任何所需的框架。 - mP.
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接