关于Java日志记录和SLF4J的思考

关于Java日志记录和SLF4J的思考_第1张图片

在这篇文章中,我将漫步于Java的登录,过去的完成方式以及SLF4J之类的库可以带来什么。

创建软件时,日志记录是基本需求。 记录用例是:

  • 在开发过程中调试软件
  • 在生产过程中帮助诊断错误
  • 出于安全目的跟踪访问
  • 创建数据以供统计使用
  • 等等

无论使用什么,日志都应该详细,可配置且可靠。

历史

过去,Java会使用System.out.println()System.err.println()e.printStackTrace()语句完成日志记录。 放置在System.out调试日志和System.err错误日志。 在生产中,两者都被重定向:前者在null输出上,后者在所需的错误日志文件中。 因此它们虽然足够有用,但存在一个很大的缺点:它们不是非常可配置的。 这是一个全有或全无的开关,无论是登录还是不登录。 您无法将详细日志集中在特定的层或包上。

关于Java日志记录和SLF4J的思考_第2张图片

Log4J进行了救援。 这是人们从日志记录框架可能想要的一切。 它发明了当今日志框架中仍然使用的许多概念(这是我使用的第一个框架,因此,如果没有发明出一个概念,请耐心等待):

  • 记录器的概念,以便可以独立配置每个记录器
  • Appender的概念,以便每个附加程序都可以在所需的任何位置(文件,数据库,消息等)进行记录
  • 级别的概念,以便可以分别配置(或不配置)每条消息的日志记录

之后,Sun感觉到需要在JDK中使用日志记录功能,但是它没有直接使用log4j,而是创建了一个受其启发的API。 但是,它的效果不如Log4J。 如果要使用JDK 1.4日志记录 ,则可能必须编写自己的Appender(称为Handlers),因为唯一可用的处理程序是现成的Console和File。

在两个框架都可用的情况下,您需要配置两个框架,因为无论使用哪种框架,您的项目中肯定至少有一个依赖项使用了另一个。 Apache Commons Logging是一个API桥,可将其自身连接到受支持的日志框架。 库应该使用公共记录,以便使用的实际框架是项目的选择,而不是依赖项所强加的。 并非总是如此,因此Commons Logging不能解决双重配置问题。 Morevoer,Commons Logging遇到一些类加载问题,从而导致NoClassDefFoundError错误。

最后,Log4J的首席程序员退出了该项目,原因是我在此不作详细说明。 他创建了另一个日志记录框架,即SLF4J,应该是Log4J v2。

一些奇怪的事实

以下事实使我对以前的框架感到困扰。 它们本身并不是缺点,但是值得一提:

  • Log4J对JMS,Mail和JMX具有Maven依赖关系,这些依赖关系不是可选的,这意味着如果您不排除它们,它们将出现在您的类路径中
  • 同样,Commons Logging对Avalon(另一个日志记录框架),Log4J,LogKit和Servlet API(!)也具有Maven依赖关系,这些依赖关系不是可选的
  • Swing日志查看器包含在Log4J jar中,即使您在无头环境(例如批处理或应用程序服务器)中使用它也是如此
  • Log4J v1.3主页正在重定向到v1.2,而Log4 v2.0是试验性的

使用哪个框架?

Log4J将是首选的框架(大多数情况下是这样),但已不再开发。 参考1.2版,放弃了1.3版,而2.0版仍处于早期阶段。

Commons Logging对于库(相对于应用程序)是一个不错的选择,但是我曾经遭受过一次类加载器问题,一次却足以否决它(最后,我抛出了Commons Logging并直接使用Log4J)。

JDK 1.4日志记录是标准的,不会引起并发版本问题。 但是它缺少这么多功能,如果不重新开发某些功能(例如数据库适配器等),就无法使用它。 太糟糕了...但是它不能回答问题:要使用哪个框架?

最近,我公司的建筑师决定使用SLF4J。 为什么要这样选择?

SLF4J

SLF4J不如Log4J普及,因为大多数架构师(和开发人员都非常了解Log4J),或者不了解SLF4J,或者不管在乎还是坚持使用Log4J。 此外,对于大多数项目,Log4J可以满足所有日志记录的需求。 然而,有趣的是,Hibernate使用SLF4J。 它具有Log4J中不存在的一些不错的功能。

简单语法

以下面的Log4J示例为例:

LOGGER.debug("Hello "+name);

由于不赞成使用String串联,因此许多公司都采用以下语法,因此只有在DEBUG级别时才进行串联:

if(logger.isDebugEnabled()){
  LOGGER.debug("Hello "+name);
}

它避免了String串联,但是有点沉重,不是吗? 相反,SLF4J提供以下简单语法:

LOGGER.debug("Hello {}",name);

这就像第一种语法,但没有连接成本,也没有沉重的语法负担。

SLF4J API和实现

此外,SLF4可以很好地将API与实现分离开来,这样您就可以使用最适合您的开发的API,并使用最适合您的生产团队的后端。 例如,您可以强制使用SL4J API,同时让生产仍然重用它们已经存在了很长时间的旧log4j.properties。 SLF4J的日志记录实现称为LogKit。

SLF4J桥接

SLF4J具有桥接功能,因此您可以从项目的依赖项中删除所有log4j和commons-logging依赖项,而仅使用SLF4J。

SLF4J为每个日志记录框架提供一个JAR:它们模仿其API,但将调用重新路由到SLF4J API(后者又使用真实的框架)。 一个警告:您可能会陷入一个循环,所以请注意不要在类路径中的实现库中包含桥接库。 例如,如果您使用Log4J桥,则每个Log4J API调用都将重新路由到SLF4J。 但是,如果存在SLF4J Log4J实现,它将再次路由回Log4J。

具有Log4J实现的SLF4J API

考虑到所有这些事实,我的建议是使用SLF4J API和Log4J实现。 这样,您仍然可以配置记录旧的Log4J方式,但是可以访问SLF4J的简单API。 为此,您必须:

行动 位置 描述

Add to classpath

slf4j-api.jar*

Main API without which you cannot use SLF4J

slf4j-log4j.jar*

SLF4J Log4J implementation

jul-to-slf4j.jar*

Enables rerouting JDK 1.4 logging calls to SLF4J

jcl-over-slf4j.jar*

Reroutes commons-logging calls to SLF4J

Remove from classpath

commons-logging.jar*

Would conflict with commons-logging API in jcl-over-slf4j.jar

SLF4JBridgeHandler.install() **

Main application

Redirect JDK 1.4 logging calls to SLF4J

 * Jar name will likely includes version

** 20% overhead advertised so do only if you need the single entry point and if there are a few calls

在应用服务器内部运行时,可能必须更改其库和/或其配置才能达到这种情况。

更进一步:
  • SLF4J项目
  • Log4J项目
  • 公用测井项目
  • Commons Logging类加载器问题

翻译自: https://blog.frankel.ch/thoughts-on-java-logging-and-slf4j/

你可能感兴趣的:(关于Java日志记录和SLF4J的思考)