《SLF4J官方文档》SLF4J-FAQ 常见问题解答(一)

  1. 云栖社区>
  2. 博客>
  3. 正文

《SLF4J官方文档》SLF4J-FAQ 常见问题解答(一)

青衫无名 2017-05-19 15:32:00 浏览1980

一般性问题

  1. 什么是SLF4J?
  2. 什么时候应该使用SLF4J?
  3. SLF4J仍是另一个日志外观吗?
  4. 如果SLF4J可修复JCL,那为什么不在JCL里加入修复而是创建一个新项目?
  5. 使用SLF4J时,我必须重新编译我的应用以转换到一个不同的日志系统吗?
  6. SLF4J的要求是什么?
  7. SLF4J向后兼容版本吗?
  8. 使用SLF4J时遇到访问权限错误,原因是什么?
  9. 为什么SLF4J是在X11类型许可证下许可而不是Apache软件许可?

10.在哪里能获得特定的SLF4J绑定?

11.我的库应该尝试配置logging吗?

12.为了减小我们软件的依赖库数量,我们想让SLF4J成为一个可选择的依赖包。这个是好主意吗?

13.Maven传递依赖怎么样?

14.如何排除依赖Maven的commons-logging?

 

关于SLF4J API

  1. 为什么日志器接口的打印方法不接收对象类型的消息,但只收String类型消息?
  2. 我可以输出一个没有消息的异常日志吗?
  3. 输出日志(关闭日志)的最快方法是什么?
  4. 如何打印单独(可能是复杂的)对象的字符串内容日志?
  5. 为什么slf4j.Logger接口没有FATAL级别的方法?
  6. 为什么TRACED级别的日志只在SLF4J 1.4.0版本介绍?
  7. SLF4J日志API支持I18N(国际化)吗?
  8. 不通过LoggerFactory里的静态方法,可以重新获取日志器吗?
  9. 存在错误/抛出异常时,可以参数化日志声明吗?

实现SLF4J API

  1. 如何使我的日志底层SLF4J可兼容?
  2. 如何使我的日志系统添加支持Marker接口?
  3. SLF4J的版本检查机制如何工作?

关于日志的一般性问题

1.类的日志器成员变量应该声明为静态变量吗?

2.类里的声明日志器有推荐的习语吗?

一般性问题

1.什么是SLF4J?

SLF4J是一个简单的日志系统外观,它允许终端用户在部署时植入所需日志系统。

2.什么时候应该使用SLF4J?

简单而言,为库和其他嵌入组件的日志需求,它们应该考虑下SLF4J,因为库不能强加终端用户日志框架的选择。另外,独立应用使用SLF4J不一定有意义。独立应用可以直接援引他们选择的日志框架。对于logback,问题是没有实际意义的,因为logback通过SLF4J暴露它的logger API。

SLF4J只是个外观,意味着它不提供一个完整的日志方案。例如配置输出源或者设置日志级别的操作不能和SLF4J执行。因此,在某个时间点上,任何微不足道的应用将需要直接援引底层日志系统。换句话说,完全对立的API底层日志系统是不可能给独立应用程序使用的。然而,SLF4J减少这种依赖的影响到无痛苦级别。

假设你的CRM应用用log4j来记录日志。然后,你的一个重要客户端请求日志要通过JDK1.4执行日志记录。如果你的应用充斥着数以千计的直接log4j调用,转移到JDK1.4的调用将相对是一个冗长和容易出错的过程。更糟的是,你可能需要维护两个版本的CRM软件。你已经引用SLF4J API而不失log4J,通过替换二者的jar文件,迁移可在几分钟内完成。

SLF4J允许组件开发人员推迟终端用户的日志系统的选择,但最终仍需要做出一个选择。

3.SLF4J仍是另一个日志外观吗?

SLF4J在概念上和JCL非常相似。因此它可以被认为是另一个日志外观。但是,SLF4J在设计上更简单和更健壮。简而言之,SLF4J避免了植入JCL的类加载问题。

4.如果SLF4J可修复JCL,那为什么不在JCL里加入修复而是创建一个新项目?

这是非常好的问题。首先,SLF4J静态绑定方法非常简单,甚至很可笑。很难说服开发者这个方法的有效性。仅仅在SLF4J发布后和开始变得被接收后,它才在相关社区里获得尊重。

其次,SLF4J提出2个改进手段,这都趋向被低估了。用务实的方法,参数化日志消息解决了一个跟日志性能联系的重要问题。标记对象,由org.slf4j.Logger接口支持,为高级日志系统的采用铺路,如果必要的话,同时让放开转回更多传统日志系统的大门。

5.使用SLF4J时,我必须重新编译我的应用以转换到一个不同的日志系统吗?

不,你不需要重新编译你的应用。你可以通过移除之前的SLF4J绑定,然后将它替换为你选择的绑定,就能转换到不同的日志系统了。

例如,如果你在使用NOP实现,希望转换到log4j 1.2版本,在你的类目录下用 slf4j-log4j12.jar 替换slf4j-nop.jar,但也别忘了添加log4j-1.2.x.jar 。像转换到JDK 1.4 logging?只需用slf4j-jdk14.jar替换slf4j-log4j12.jar

6.SLF4J的要求是什么?

1.7.0版本SLF4J需要JDK1.5以上。早期的SLF4J版本,像SLF4J 1.4,1.5和1.6,要求JDK1.4。

 

Binding Requirements
slf4j-nop JDK 1.5
slf4j-simple JDK 1.5
slf4j-log4j12 JDK 1.5, plus any other library dependencies required by the log4j appenders in use加入任何其他所需的依赖包取决于使用的log4j输出源
slf4j-jdk14 JDK 1.5 or later
logback-classic JDK 1.5 or later, plus any other library dependencies required by the logbackappenders in use加入任何其他所需的依赖包取决于使用的log4j输出源

7.SLF4J向后兼容版本吗?

从客户端角度,SLF4J API对所有版本都向后兼容。这意味着你能从SLF4J版本1.0升级到任何以后的版本,没有任何问题。对于slf4j-api版本N和slf4j-api

版本M, 版本N编译的代码将和版本M编译的代码一起正常运作。迄今为止, slf4j-api里的二进制兼容性从来没有被打破。

然而,从客户端角度,SLF4J API非常稳定时,SLF4J绑定,比如slf4j-simple.jar

或slf4j-log4j12.jar,需要一个特定版本的SLF4J-API。混合不同版本的slf4j可能会出现问题和强烈不提倡的。例如,如果你正在使用slf4j-api-1.5.6.jar,然后你也应该使用slf4j-simple-1.5.6.jar,使用slf4j-simple-1.4.2.jar将不会工作。

在初始化时时,如果SLF4J推测可能有版本不匹配问题,它将发出一个关于不匹配的警告。

8.使用SLF4J时遇到访问权限错误,原因是什么?

如下是错误详情:

1 Exception in thread "main" java.lang.IllegalAccessError: tried to access field
2 org.slf4j.impl.StaticLoggerBinder.SINGLETON from class
3 org.slf4j.LoggerFactory    at
4 org.slf4j.LoggerFactory.<clinit>(LoggerFactory.java:60)

这个问题是由LoggerFactory类的静态初始化尝试直接访问org.slf4j.impl.StaticLoggerBinder的单例变量造成的。这在SLF4J 1.5.5和之前的版本允许,在1.5.6及以后的版本,单例变量已经被标记为私有访问权限了。

如果你遇到了上述的错误,你可以用老版本的slf4j-api,比如1.4.3,同时使用一个新版本的slf4j绑定,比如1.5.6。通常,当你的Maven pom.xml文件使用hibernate 3.3.0,在slf4j-api 1.4.2版本上声明一个依赖时,将发生上述异常。如果你的pom.xml在slf4j绑定上声明依赖,比方说slf4j-log4j12 版本1.5.6,你会触发非法访问错误。

查看Maven里那个slf4j-api版本被拉入,用下述maven依赖植入。

1 mvndependency:tree

如果你使用Eclipse,请不要依靠m2eclipse显示的关系树。
如果你的pom.xml明确在slf4j-api上声明了依赖,这个版本的api匹配已声明的绑定,将使这个问题消失。
也请读向后兼容性的FAQ,以获得更多普遍性解释。
9.为什么SLF4J是在X11类型许可证下许可而不是Apache软件许可?
SLF4J是在X11类型许可证下许可而不是Apache软件许可,这是因为X11许可是被Apache软件基金会以及自由软件基金会的各自许可认为是科兼容的。
10.在哪里能获得特定的SLF4J绑定?

SimpleLoggerNOPLoggerog4jLoggerAdapterJDK14LoggerAdapter 的SLF4J绑定包含在slf4j-nop.jarslf4j-simple.jar,slf4j-log4j12.jar, and slf4j-jdk14.jar文件里。

给logback-classic的绑定附带在logback distribution(http://logback.qos.ch/download.html)上。对于其他所有的绑定,logback-classice绑定需要slf4j-api.jar。

11.我的库应该尝试配置logging吗?

嵌入的组件,比如库,不进不需要配置底层日志框架,它们也不应该做这些。它们应该引入SLF4j来记录日志,但也应该让终端用户配置日志环境。当嵌入的组件尝试在自己配置日志时,它们常常会覆盖终端用户的意愿。在一天的结束时,终端用户不得不读日志,处理日志。她应该是决定自己想要的日志配置的人。

12.为了减小我们软件的依赖库数量,我们想让SLF4J成为一个可选择的依赖包。这个是好主意吗?

当一个软件工程到达它需要设计日志策略的点时,这个问题会提起 。

让Wombat成为一个具有极少依赖的软件库。如果SLF4J被选作为Wombat的日志API,那么一个新的slf4j-api.jar依赖库将被加入带Wombat的依赖包列表中。由于写日志的包装并不难,一些开发者冒险包装SLF4J,只有当它已经出现在类路径中时链接它,使得SLF4J成为Wombat的一个可选择的依赖库。为了解决这个依赖问题,包装将被从SLF4J的API中隔离Wombat,以确保Wombat中的日志不会过时的。

另外,任何SLF4J-包装都取决于SLF4J得定义。它们一定有相同的通用api。在将来,如果出现一个新的、明显不同的日志API,和直接使用SLF4J的代码一样,使用包装器的代码也将同样很难移植到新的API.因此,包装器不可能是面向未来的代码,但在SLF4J上增加了一个额外的间接连接,使得这更复杂,这本身就是一中间接连接。

脆弱性增加实际上比这个还遭。包装器需要依赖随时变化的一些内部SLF4J接口,这违背了面向客户端API永不改变的原则。因此,包装器通常依赖一些同他们一起编译的主要版本。针对SLF4J 1.5.x版本编译的包装器将不会同SLF4J 版本1.6工作,但是使用org.slf4j.Logger, LoggerFactory, MarkerFactory, org.slf4j.Marker和MDC的客户端代码将和任何版本SLF4J 1.0及以后的版本正常工作。合理地假设在大部分工程中,Wombat将是许多依赖库中的一个。如果每个依赖库有自己日志包装器,那么大概每个包装器需要独立配置。因此,不只是处理SLF4J的日志框架,Wombat的用户也必须处理Wombat的日志包装器。

为了使SLF4J可选择,每个框架提出的自己的包装器将加剧这个问题。(配置或处理5个不同的日志包装器将很不愉快,也不招人喜欢)

Velocity项目采纳的日志策略 是一个“自定义日志抽象”反模式的好例子。通过采用一个独立的日志抽象的策略,Velocity开发者已经使自己的开发更复杂,但更重要的是,他们让开发对他们的用户更难。

一些项目试着在类路劲上检测SLF4J的存在性,如果存在的话就转换到SLF4J.虽然这个方法看上去足够的透明,但是它将导致错误的位置信息。底层日志框架将打印包装器的位置(类名和行数)而不是打印真正调用者的位置。还有就是除了参数化日志、像SLF4J支持MDC和标记的API覆盖问题。尽管有人可以在数小时内提出一个似乎可运行的SLF4J包装器,随着时间的推移,许多技术问题将出现,这是Wombat开发者不得不处理的问题。注意SLF4J已经发展了好几年了,有260个bug报告提起它。

基于以上原因,框架的开发者应该抵制自己写的日志包装的诱惑。 它不仅是浪费开发者时间,对上述日志的用户,这实际上让开发更困难,使日志代码自相矛盾地更容易改变。

13.Maven传递依赖怎么样?

作为使用Maven构建库作者,你可能想使用绑定来测试你的应用程序,比如SLF4J-log4j12或的logback经典,对用户不强制log4j或logback-classic作为依赖。 这是比较容易做到的。

基于你的库的代码依赖于SLF4J API,你需要声明SLF4J的API作为一个编译时(默认范围)的依赖。

1 <dependency>
2   <groupId>org.slf4j</groupId>
3   <artifactId>slf4j-api</artifactId>
4   <version>1.7.21</version>
5 </dependency>

通过声明SLF4J绑定依赖为“测试”的范围,可以实现限制在测试绑定使用的SLF4J的传递。例如:

1 <dependency>
2   <groupId>org.slf4j</groupId>
3   <artifactId>slf4j-log4j12</artifactId>
4   <version>1.7.21</version>
5   <scope>test</scope>
6 </dependency>

 

因此,至于你的用户要导出SLF4J的API作为库的传递依赖,但不是任何SLF4J绑定或任何底层日志系统。

需要注意的是由于SLF4J 1.6版,在没有SLF4J绑定,SLF4J的API将默认为无无操作实现。

14.如何排除依赖Maven的commons-logging?

替代1明确排除

很多使用Maven的软件项目声明commons-logging作为一个依赖。因此,如果你希望迁移到SLF4J或使用jcl-over-slf4j,你需要排除项目中所有依赖里的comms-logging,这些依赖库传递依赖common-logging。依赖排除 在Maven文件里已有描述。为分布在几个pom.xml里的多个依赖明确地排除common-logging,可能是一个笨重的和相对容易出错的过程。

替代2规定的范围

在项目的pom.xml文件中所提供的范围内,通过声明Commons-logging,它可以像依赖一样简单、方便地排除。实际的commons-logging类将由jcl-over-slf4j提供。 这转化为以下POM文件片段:

01 <dependency>
02   <groupId>commons-logging</groupId>
03   <artifactId>commons-logging</artifactId>
04   <version>1.1.1</version>
05   <scope>provided</scope>
06 </dependency>
07  
08 <dependency>
09   <groupId>org.slf4j</groupId>
10   <artifactId>jcl-over-slf4j</artifactId>
11   <version>1.7.21</version>
12   </dependency>

 

第一依赖性声明本质规定commons-logging会通过你的环境“以某种方式”提供。第二个声明引入jcl-over-slf4j到你的项目中。 作为jcl-over-slf4j是commons-logging完美的二进制兼容更换,第一个断言为真。

不幸的是,虽然在规定范围内声明的commons-logging能够完成任务,你的IDE,比如Eclipse中,仍将在项目的类路径上放置commons-logging.jar,通过你的IDE可以看到。 您将需要确保jcl-over-slf4j前,您的IDE 的commons-logging.jar的是可见的。

转载自 并发编程网 - ifeve.com