【问题标题】:How to suppress SLF4J Warning about multiple bindings?如何抑制关于多个绑定的 SLF4J 警告?
【发布时间】:2011-11-26 03:44:48
【问题描述】:

我的 java 项目依赖于不同的 SLF4J 版本。如何抑制烦人的警告?

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:xyz234/lib/slf4j-
log4j12-1.5.8.jar!/org/slf4j/impl/StaticLoggerBinder.class]

SLF4J: Found binding in [jar:file:xyz123/.m2/repository/org/slf4j/slf4j-log4j12
/1.6.0/slf4j-log4j12-1.6.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

P.S.:这与slf4j warning about the same binding being duplicate 不是同一个问题,答案是如何消除误报警告,但在我的情况下,这是一个真正的警告。 P.S.S.:对不起,我忘了说:我使用 Maven 并且 SLF4J 包含在我的依赖项的依赖项中。

【问题讨论】:

  • 接受一个答案,如果它对解决问题有用,或者如果你自己解决了,你可以添加你自己的答案并接受它。

标签: maven binding warnings slf4j suppress


【解决方案1】:

从类路径中删除slf4j-log4j12-1.5.8.jarslf4j-log4j12-1.6.0.jar 之一。您的项目不应依赖于不同版本的 SLF4J。我建议你只使用 1.6.0。

如果你使用 Maven,你可以exclude transitive dependencies。这是一个例子:

<dependency>
    <groupId>com.sun.xml.stream</groupId>
    <artifactId>sjsxp</artifactId>
    <version>1.0.1</version>
    <exclusions>
        <exclusion>
            <groupId>javax.xml.stream</groupId>
            <artifactId>stax-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

使用current slf4j-api implementation 无法删除这些警告。 org.slf4j.LoggerFactory 类打印消息:

  ...
  if (implementationSet.size() > 1) {
    Util.report("Class path contains multiple SLF4J bindings.");
    Iterator iterator = implementationSet.iterator();
    while(iterator.hasNext()) {
      URL path = (URL) iterator.next();
      Util.report("Found binding in [" + path + "]");
    }
    Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
  }
  ...

Util 类如下:

public class Util {

  static final public void report(String msg, Throwable t) {
    System.err.println(msg);
    System.err.println("Reported exception:");
    t.printStackTrace();
  }
  ...

report 方法直接写入System.err。解决方法可能是将System.err 替换为System.setErr()第一个LoggerFactory.getLogger() 调用之前,但如果这样做,您可能会丢失其他重要消息。

当然,您可以下载源代码并删除这些 Util.report 调用,然后在您的项目中使用您修改后的 slf4j-api。

【讨论】:

  • 这将修复警告,但我只想抑制它,因为在我的情况下(Maven)似乎无法修复。
  • 啊,非常感谢,这很有帮助!尤其是您深入研究了 SLF4J 类的源代码。
  • 正确地接受了答案。抱歉花了这么长时间我完全忘了接受它!
【解决方案2】:
    PrintStream filterOut = new PrintStream(System.err) {
        public void println(String l) {
            if (! l.startsWith("SLF4J")) {
                super.println(l);
            }
        }
    };
    System.setErr(filterOut);

瞧!

【讨论】:

  • 这已经在近三年前接受的答案中讨论过(“一种解决方法可能是用 System.setErr() 替换 System.err”),以及这种方法的问题( “如果你这样做,你可能会丢失其他重要信息。”)。
【解决方案3】:

您是否阅读了警告所引用的 URL?

SLF4J: See [http://www.slf4j.org/codes.html#multiple_bindings][1] for an explanation.

链接说明如下:

SLF4J API 旨在与一个且仅一个底层日志绑定 一次框架。如果类中存在多个绑定 路径,SLF4J 将发出警告,列出这些路径的位置 绑定。发生这种情况时,请选择您唯一的一个绑定 希望使用,并删除其他绑定。

例如,如果您同时拥有 slf4j-simple-1.6.2.jar 和 slf4j-nop-1.6.2.jar 在类路径上,您希望使用 nop (无操作)绑定,然后将 slf4j-simple-1.6.2.jar 从 类路径。

请注意,SLF4J 发出的警告只是一个警告。 SLF4J 仍将与它在类路径中找到的第一个框架绑定。

【讨论】:

  • 正如我所写,我的项目是一个 Maven 项目。我确切地知道这个警告说什么,我只是无法控制我的依赖项在 Maven 中使用的依赖项。我知道这只是一个警告,但它掩盖了我的控制台输出,因此我想摆脱它。 P.S.:对不起,我忘了提到我使用 Maven。
  • (只是为了后代)这与 maven 无关:您可以控制您的依赖项的依赖项(如图所示)。当项目创建"uber" jar combining multiple jars into one 时,仍然会出现问题(无论是否使用 maven)。然后你必须找到并使用原来的罐子。如果不使用 maven,您可以手动从 uber jar 中删除有问题的类,但这是一个糟糕的解决方法。但即使使用 maven,您也可以“修复”原始 uber jar 并将其上传到内部存储库。
  • 不处理我的案子。我写了一个围绕 logback 的包装器。我真的想要类路径中的两个绑定。有什么建议吗?
【解决方案4】:

如果使用 maven 总是使用命令

mvn dependency:tree

这将列出添加到项目中的所有依赖项,包括对我们包含的 jar 的依赖项。在这里,我们可以确定多个版本,或者与添加的其他 jar 一起提供的多个 jar 副本。使用

<exclusions><exclusion><groupId></groupId><artifactId></artifactId></exclusion></exclusions>

&lt;dependency&gt; 元素中排除冲突的元素。如果问题仍然存在,请务必在每次排除后重新运行上述 maven 命令。

【讨论】:

    【解决方案5】:

    有时从类路径中排除第二个记录器需要太多的扭曲,并且警告非常烦人。在程序开始时屏蔽标准错误似乎确实有效,例如

        public static void main(String[] args)
        {
            org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.OFF);
            PrintStream old = System.err;
            System.setErr(new PrintStream(new ByteArrayOutputStream()));
            // ... trigger it ...
            System.setErr(old);
    
            ...
    

    trigger it 部分应该调用一些访问日志系统的 nop 函数,否则会导致生成消息。

    我不建议将其用于生产代码,但对于 skunkworks 而言,它应该会有所帮助。

    【讨论】:

      【解决方案6】:

      如果您使用的是旧版本的 Jetty(例如 Jetty 6),您可能需要更改 webapp 的类加载顺序,使其优先级高于容器的优先级。您可以通过将此行添加到容器的 xml 文件中来做到这一点:

      <Set name="parentLoaderPriority">false</Set>
      

      【讨论】:

        猜你喜欢
        • 2017-06-08
        • 1970-01-01
        • 2021-05-19
        • 1970-01-01
        • 2022-10-15
        • 2013-01-28
        • 2010-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多