java中slf4j日志
在这篇文章中,我将漫步于Java的登录,过去的日志记录以及SLF4J之类的库可以带来什么。
创建软件时,日志记录是基本需求。 记录用例是:
- 在开发过程中调试软件
- 在生产过程中帮助诊断错误
- 出于安全目的跟踪访问
- 创建数据以供统计使用
- 等等
无论使用什么,日志都应该详细,可配置且可靠。
历史
过去,Java会使用System.out.println()
, System.err.println()
或e.printStackTrace()
语句完成日志记录。 放置在System.out
调试日志和System.err
错误日志。 在生产中,两者都被重定向:前者在null输出上,后者在所需的错误日志文件中。 因此它们虽然足够有用,但存在一个很大的缺点:它们不是非常可配置的。 这是一个全有或全无的开关,无论是登录还是不登录。 您无法将详细日志集中在特定的层或包上。
Log4J进行了救援。 这就是日志框架可能想要的一切。 它发明了当今日志框架中仍然使用的许多概念(这是我使用的第一个框架,因此,如果没有发明出一个概念,请耐心等待):
- 记录器的概念,以便可以独立配置每个记录器
- Appender的概念,以便每个附加程序都可以在所需的任何位置(文件,数据库,消息等)进行记录
- 级别的概念,以便可以分别配置(或不配置)每条消息的日志记录
之后,Sun感觉到需要在JDK中使用日志记录功能,但是它不是直接使用log4j,而是创建了一个受其启发的API。 但是,它的效果不如Log4J。 如果要使用JDK 1.4日志记录 ,则可能必须编写自己的Appender(称为处理程序),因为可用的唯一处理程序是现成的控制台和文件。
在两个框架都可用的情况下,您需要配置两个框架,因为无论使用哪种框架,项目中肯定至少有一个依赖项使用了另一个。 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);
由于不赞成使用字符串串联,因此许多公司都采用以下语法,因此只有在处于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 |
| 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 |
在应用服务器内部运行时,可能必须更改其库和/或其配置才能达到这种情况。
翻译自: https://blog.frankel.ch/thoughts-on-java-logging-and-slf4j/
java中slf4j日志