《SLF4J官方文档》SLF4J警告或错误信息及其含义

原文地址

调用方法o.a.commons.logging.impl.SLF4FLogFactory.release

已给出的公用日志API(common-logging API),实际上是由SLF4J实现的,o.a.commons.logging.impl.SLF4FLogFactory.release方法永远不会被调用。然而,取决于commons-logging.jar在服务器小程序容器的部署,release()方法可能意外地通过commons-logging.jar装载的org.apache.commons.logging.LogFactoryl类被调用。

当Tomac安装后,$TOMAC_HOME代表目录;在最近的Tomac版本上,这是个普遍的现象,尤其当你在应用中在WEB-INF/lib下放置jcl-over-slf4j.jar而不是在$TOMCAT_HOME/common/lib下放置jar包。为了完全获得jcl-over-slf4j.jar包的稳定性,我们建议你在$TOMCAT_HOME/common/lib目录下放置jcl-over-slf4j.jar包,没有在你的web应用里放置副本。

也请你看下bug#22

jcl-over-slf4j不支持的[某个]操作

当调用JCL1.1中受保护的方法,会抛出不支持操作异常 (UnsupportedOperationException)。这些方法都是通过commons-logging.jarLogFactory 实现调用。 当然,LogFactoryjcl-over-slf4j.jar包下的SLF4FLogFactory实现,SLF4FLogFactory不调用这些方法。

如果你研究这个问题,很大可能是你的commons-logging.jar副本在类的路径下覆盖了jcl-over-slf4j.jar包中的类。

当调用o.a.commons.logging.impl.SLF4FLogFactory.release()方法时,注意实际上这个问题跟发出的警告是非常相似的,已在前一个章节讨论了。

日志名称不匹配检测

只有slf4j.detectLoggerNameMismatch系统属性设置为true时,日志名称不匹配警告才会打印。默认情况下,这个属性没有设置,即使在日志名称不匹配的情况下也不会打印警告。

从1.7.9开始,在指定名称的日志器下,向LoggerFactory.getLogger(Class)方法传参,警告信息就会被打印,这个方法和SLF4J内部推断的调用者的名称不同。

例如,代码块如下:


package com.acme;
import com.foo.Kangaroo;

class <strong>Fruit</strong> {
Logger logger = LoggerFactory.getLogger(Kangaroo.class);
}

结果将会显示:


SLF4J: Detected logger name mismatch. Given name:

"com.foo.Kangaroo"; computed name: "com.acme.Fruit".

但只在slf4j.detectLoggerNameMismatch系统属性设置为true时才显示。

当日志器中传入的参数类是一个基类,这种特定情况下子类不会出现任何警告信息,例如:


class A {
Logger logger = LoggerFactory.getLogger(getClass());
}
class B extends A {
// no mismatch warning will be issued when B is instantiated
// given that class A is a super-type of class B
}

如果你遇到不能解释的不匹配警告,你可以用白色大象标记它,当定义了日志器,这种不能正确推断出类名的情况是非常少的。我们也很有兴趣去获得这些类。如果你标记了一个无法解释的不匹配信息,请给我们发一个[日志报告]( http://www.slf4j.org/bug-reporting.html)文件。

加载org.slf4j.impl.StaticLoggerBinder类失败

当org.slf4j.impl.StaticLoggerBinder类不能从内存中加载是,将会报告这个错误信息。当在类路径中没有合适的SLF4J绑定时,这种情况会发生。放置一个jar包(只能放其中的一个):slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar, logback-classic.jar。在类路径中放置一个就可以解决问题。

从1.6.0: 1.6版本的SLF4J,没有绑定,SLF4J默认是一个无操作日志实现。

你可以从项目下载页(http://www.slf4j.org/download.html)下载SLF4J绑定。

在类路径下发现多个绑定

SLF4J被设计成依次与每个且只有一个基本日志框架绑定。如果在类路径下存在不止一个绑定。SLF4J将发出一个警告,列出这些绑定的位置。

当多个绑定在类路径下,只能选取一个你想用的绑定,移除其他绑定。比如,如果在类路径下同时有slf4j-simple-1.7.19.jar和 slf4j-nop-1.7.19.jar,你想用无操作绑定,那么把slf4j-nop-1.7.19.jar从类路径中移除。

这个SLF4J提供的警告信息位置列表 为识别过渡添加到项目中不想要的SLF4J绑定依赖包 提供了有效的信息。在项目中pom.xml文件中,剔除掉那些随意声明的依赖包下的SLF4J绑定。例如,cassandra-all版本0.0.1同时把log4jslf4j-log4j12声明为编译时间关联。由此,当你把cassandra-all作为依赖包包含到你的项目中,cassandra-all声明将导致log4jslf4j-log4j12同时被添加为依赖包。假使SLF4J在后台时,你不想用log4J,你可以告诉Maven这俩个文件,如下文显示:


<dependencies>
 <dependency>
  <groupId> org.apache.cassandra</groupId>
  <artifactId>cassandra-all</artifactId>
  <version>0.8.1</version>

  <exclusions>
   <exclusion>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
   </exclusion>
   <exclusion>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
   </exclusion>
  </exclusions>

 </dependency>
</dependencies>

注意:SLF4J发出的警告只是警告。甚至多个绑定存在时,SLF4J将选取一个日志框架/实现,然后与它绑定。SLF4J选取绑定的方式由java虚拟机决定,应该随机考虑所有的实际目的。1.6.6版本,SLF4J会以框架/实现类的实际范围命名。

例如类库或框架的这些嵌入的组件不能声明任何SLF4J的绑定,除了依赖slf4j-api。当一个包库在SLF4J绑定上声明一个编译时间依赖,它会欺骗你并且绑定到最后的用户,这样就与 SLF4J的目的背道而驰了。当你遇到嵌入组件在SLF4J绑定上声明编译时间依赖,请及时联系这些作者,友好地请他们修复这些方法。

Slf4j-api版本不匹配绑定

SLF4J绑定标明人工打的jar包,例如用来把slf4j绑定到基本日志框架的slf4j-jdk14.jar 或 slf4j-log4j12.jar,java.util.logging和个别log4j。

混用不同版本的slf4j-api.jar和SLF4J绑定会导致问题。例如,如果你用slf4j-api-1.7.19.jar,然后你也应该用slf4j-simple-1.7.19.jar,用slf4j-simple-1.5.5.jar将不起作用。

注意: 从客户端的角度,所有版本的slf4j-api版本都是兼容的。在任意N和M版本slf4j-api下,通过slf4j-api-N.jar编译的客户端代码在slf4j-api-M.jar下也将运行良好。你只需确定绑定版本匹配slf4j.jar。你不需要担心项目中已给出的依赖库slf4j-api的版本。你能用任意slf4j-api.jar版本,只要slf4j-api.jar版本和它的绑定匹配,就不会有问题。

在初始化时,如果SLF4J怀疑有任任何api和绑定版本不匹配问题,它将发出被疑似不匹配的警告信息。

日志工厂实现不能为空

这个错误在LoggerFactory类找不到合适的绑定时会报告。在类路径下放置slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar logback-classic.jar中的一个包(只能放一个),这会是个有效的改正方法。

在类路径下检测log4j-over-slf4j.jar和 slf4j-log4j12.jar包,替代堆溢出错误

slf4j-log4j12 模块的目的是把从log4j日志到SLF4J的调用转移或重定向。Log4j-over-slf4j模块的目的是把从Log4j-over-slf4j日志到SLF4J的日志记录重定向。如果SLF4J属于slf4j-log4j12.jar和slf4j-log4j-over-slf4.jar,也会在出现在类路径中,堆溢出错误必然会在第一次调用SLF4J或log4j日志时出现。

如下是类似的异常:


Exception in thread "main" java.lang.StackOverflowError
at java.util.Hashtable.containsKey(Hashtable.java:306)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:36)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.log4j.Category.<init>(Category.java:53)
at org.apache.log4j.Logger..<init>(Logger.java:35)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:39)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.log4j.Category..<init>(Category.java:53)
at org.apache.log4j.Logger..<init>(Logger.java:35)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:39)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
subsequent lines omitted...

SINCE 1.5.11  SLF4j取代了必然发生的堆溢出错误,通过抛出一个关于问题实际情况的详情的异常。这比让用户去想堆溢出错误的原因要好多了。

更多其他关于这个主题的更多背景,查看Bridging legacy APIs(http://www.slf4j.org/legacy.html)。

在类路径下检测jcl-over-slf4j.jar 和 slf4j-jcl.jar包,替代堆溢出错误

slf4j-jcl模块的目的是把从SLF4J到JCL(jakarta commons logging)的调用转移或重定向。jcl-over-slf4j模块的目的是从JCL日志到SLF4J的日志记录转移或重定向。如果SLF4J属于jcl-over-slf4j.jar和slf4j-jcl.jar,也会在出现在类路径中,堆溢出错误必然会立即在第一次调用SLF4J或JCL日志时出现。

如下是类似的异常:


Exception in thread "main" java.lang.StackOverflowError
at java.lang.String.hashCode(String.java:1482)
at java.util.HashMap.get(HashMap.java:300)
at org.slf4j.impl.JCLLoggerFactory.getLogger(JCLLoggerFactory.java:67)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:289)
at org.slf4j.impl.JCLLoggerFactory.getLogger(JCLLoggerFactory.java:69)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
subsequent lines omitted...

从版本 1.5.11开始  SLF4j取代了必然发生的堆溢出错误,通过抛出一个关于问题实际情况的详情的异常。这比让用户去想堆溢出错误的原因要好多了。

更多其他关于这个主题的更多背景,查看Bridging legacy APIs

加载类” org.slf4j.impl.StaticMDCBinder”失败

这个错误表明在类路径下没找到合适的SLF4J绑定。在类路径下放置slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar logback-classic.jar中的一个包(只能放一个)会解决这个问题。

MDCAdapter不能为空

当org.slf4j.MDC class类没有被正确地初始化时会报告此错误。像上面已列出的项一样的情况和改正方案。

 

在初始化阶段拦截一定数量(N)的日志记录,现在重新显示。这些遵循底层日志系统过滤规则

从1.7.版本,在初始化阶段产生的日志记录被记录下来,然后在初始化完成后重新显示。注意重新显示的日志记录遵循底层日志系统过滤规则。

原则上,应用中重新显示出现在第一次日志记录发生时,这时多线程已经启动。

查看substitute loggers

在底层日志系统的默认配置阶段创建替代日志器

像logback和log4j这样的高级可配置日志系统,它们会在自身初始化过程中创建可调用日志器的组件。查看典型的事件LOGBACK-127(http://jira.qos.ch/browse/LOGBACK-127),它不可能实现这样的日志创建请求。

为了避免这种鸡和蛋问题,在这个过程中(初始化),SLF4J创建了替代日志器。在此阶段替代日志器的记录被简单地扔掉了。在初始化完成后,替代日志器将转移记录早合适的日志器实现,不然将会作用在LogFactory返回的日志器上。

如果已创建任何替代日志器,SLF4J将发出一个日志的列表。这个列表意欲让你知道在初始化过程中被这些日志器抛弃的任何日志记录。

查看intercepted and replayed logging calls

SLF4J 1.4.0版本,需要1.2.12及以上的版本

在2005.8.29发布的log4j1.2.12版本增加了跟踪等级。在2007.5.16的SLF4J API中增加了跟踪等级。这样,,启动SLF4J1.4.0时,绑定给SLF4J的log4j需要log4j1.2.12及其以上的版本。

当然,像在文件59报告的一样(http://jira.qos.ch/browse/SLF4J-59),在你某些环境下,这可能会很难升级log4j版本。为了解决这样的情况,SLF4J的Log4jLOggerAdapter将把跟踪等级指为调试级别。

 

java.lang.NoClassDefFoundError: org/slf4j/event/LoggingEvent

Logback-classic version 1.1.4及其以后的版本需要1.7.15及其以上版本的slf4j-api。

类路径中的早期slf4j-api.jar,1.1.4及其以后的logback版本返回的试图内省的日志实例将导致类似于下面显示的NoClassDefFoundError。


Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/event/LoggingEvent
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2451)
at java.lang.Class.privateGetPublicMethods(Class.java:2571)
at java.lang.Class.getMethods(Class.java:1429)
at java.beans.Introspector.getPublicDeclaredMethods(Introspector.java:1261)
at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1122)
at java.beans.Introspector.getBeanInfo(Introspector.java:414)
at java.beans.Introspector.getBeanInfo(Introspector.java:161)

在类路径下放置1.7.15及其以上的slf4j-api.jar包可以解决此问题。

记住这个问题只会出现在1.1.4及其以后的logback版本,其他的绑定,例如slf4j-log4j, slf4j-jdk14 and slf4j-simple是不受影响的。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/117241.html

(0)
上一篇 2021年8月28日
下一篇 2021年8月28日

相关推荐

发表回复

登录后才能评论