如何使用 slf4j 和不同的日志实用程序设置 4 个 Maven 项目?

How to setup 4 Maven projects with slf4j and different logging utilities?

所以我有 4 个 Maven 项目,我们称它们为 A、B、C 和 D。项目 A 依赖于项目 B 依赖于项目 C,项目 A 也依赖于项目 D。

D
^
|
A -> B -> C

项目 A 和 B 使用 slf4j
项目 C 使用 java.util.logging
项目 D 使用 log4j

现在我真的不知道如何设置它的日志依赖项以使其正常工作。

我有的是:
项目 D 依赖 log4j,仅此而已。
项目 C 不依赖任何东西,因为它只使用 java 的日志实用程序。
项目 B 依赖 slf4j-api 以及 jul-to-slf4j 来记录 C 记录的内容
项目 A 依赖于 slf4j-apislf4j-log4j12log4j

项目 A 是我想要 运行 的主程序。它有一个 log4j.properties 文件设置用于记录到控制台。

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

# Direct all messages there
log4j.rootLogger = INFO, stdout

现在的问题是,当我启动程序时,所有 slf4j 日志都将被忽略。我尝试在项目 A 中使用 log4j-Logger 记录一些东西,但它被记录下来了。

项目 A 的依赖关系树:

[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ devopstool ---
[INFO] PROJECT A
[INFO] +- com.google.code.gson:gson:jar:2.3.1:compile
[INFO] +- org.antlr:antlr-runtime:jar:3.4:compile
[INFO] |  +- org.antlr:stringtemplate:jar:3.2.1:compile
[INFO] |  \- antlr:antlr:jar:2.7.7:compile
[INFO] +- org.tmatesoft.svnkit:svnkit:jar:1.8.9:compile
[INFO] |  +- com.jcraft:jsch.agentproxy.svnkit-trilead-ssh2:jar:0.0.7:compile
[INFO] |  |  \- com.jcraft:jsch.agentproxy.core:jar:0.0.7:compile
[INFO] |  +- net.java.dev.jna:jna-platform:jar:4.1.0:compile
[INFO] |  +- net.java.dev.jna:jna:jar:4.1.0:compile
[INFO] |  +- com.trilead:trilead-ssh2:jar:1.0.0-build217:compile
[INFO] |  +- com.jcraft:jsch.agentproxy.connector-factory:jar:0.0.7:compile
[INFO] |  |  +- com.jcraft:jsch.agentproxy.usocket-jna:jar:0.0.7:compile
[INFO] |  |  |  \- net.java.dev.jna:platform:jar:3.4.0:compile
[INFO] |  |  +- com.jcraft:jsch.agentproxy.usocket-nc:jar:0.0.7:compile
[INFO] |  |  +- com.jcraft:jsch.agentproxy.sshagent:jar:0.0.7:compile
[INFO] |  |  \- com.jcraft:jsch.agentproxy.pageant:jar:0.0.7:compile
[INFO] |  +- de.regnis.q.sequence:sequence-library:jar:1.0.3:compile
[INFO] |  \- org.tmatesoft.sqljet:sqljet:jar:1.1.10:compile
[INFO] +- org.tmatesoft.svnkit:svnkit-cli:jar:1.8.9:compile
[INFO] +- org.tmatesoft.svnkit:svnkit-javahl16:jar:1.8.9:compile
[INFO] |  \- org.apache.subversion:svn-javahl-api:jar:1.8.1:compile
[INFO] +- com.jgoodies:forms:jar:1.2.1:compile
[INFO] +- org.jsoup:jsoup:jar:1.8.2:compile
[INFO] +- PROJECT D
[INFO] |  +- com.google.guava:guava:jar:18.0:compile
[INFO] |  +- javax.activation:activation:jar:1.1:compile
[INFO] |  +- log4j:log4j:jar:1.2.17:compile
[INFO] |  +- com.jcraft:jsch:jar:0.1.52:compile
[INFO] |  \- org.jetbrains:annotations:jar:13.0:compile
[INFO] +- PROJECT B
[INFO] |  +- org.apache.chemistry.opencmis:chemistry-opencmis-client-impl:jar:0.9.0:compile
[INFO] |  |  +- org.apache.chemistry.opencmis:chemistry-opencmis-client-api:jar:0.9.0:compile
[INFO] |  |  +- org.apache.chemistry.opencmis:chemistry-opencmis-commons-api:jar:0.9.0:compile
[INFO] |  |  +- org.apache.chemistry.opencmis:chemistry-opencmis-commons-impl:jar:0.9.0:compile
[INFO] |  |  |  +- org.codehaus.woodstox:woodstox-core-asl:jar:4.2.0:compile
[INFO] |  |  |  |  +- javax.xml.stream:stax-api:jar:1.0-2:compile
[INFO] |  |  |  |  \- org.codehaus.woodstox:stax2-api:jar:3.1.1:compile
[INFO] |  |  |  \- com.sun.xml.ws:jaxws-rt:jar:2.1.7:compile
[INFO] |  |  |     +- javax.xml.ws:jaxws-api:jar:2.1:compile
[INFO] |  |  |     +- com.sun.xml.stream.buffer:streambuffer:jar:0.9:compile
[INFO] |  |  |     +- com.sun.org.apache.xml.internal:resolver:jar:20050927:compile
[INFO] |  |  |     \- org.jvnet:mimepull:jar:1.3:compile
[INFO] |  |  +- org.apache.chemistry.opencmis:chemistry-opencmis-client-bindings:jar:0.9.0:compile
[INFO] |  |  \- org.apache.felix:org.osgi.core:jar:1.0.0:compile
[INFO] |  +- org.alfresco.cmis.client:alfresco-opencmis-extension:jar:0.3:compile
[INFO] |  +- org.slf4j:slf4j-api:jar:1.7.7:compile
[INFO] |  +- commons-configuration:commons-configuration:jar:1.10:compile
[INFO] |  |  +- commons-lang:commons-lang:jar:2.6:compile
[INFO] |  |  \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] |  +- PROJECT C
[INFO] |  |  +- javax.xml.bind:jaxb-api:jar:2.2.7:compile
[INFO] |  |  +- com.sun.xml.bind:jaxb-impl:jar:2.2.7:compile
[INFO] |  |  |  +- com.sun.xml.bind:jaxb-core:jar:2.2.7:compile
[INFO] |  |  |  |  \- com.sun.istack:istack-commons-runtime:jar:2.16:compile
[INFO] |  |  |  \- com.sun.xml.fastinfoset:FastInfoset:jar:1.2.12:compile
[INFO] |  |  |     \- javax.xml.bind:jsr173_api:jar:1.0:compile
[INFO] |  |  +- com.sun.xml.messaging.saaj:saaj-impl:jar:1.3.23:compile
[INFO] |  |  |  +- javax.xml.soap:javax.xml.soap-api:jar:1.3.5:compile
[INFO] |  |  |  +- org.jvnet.mimepull:mimepull:jar:1.9:compile
[INFO] |  |  |  \- org.jvnet.staxex:stax-ex:jar:1.7.4:compile
[INFO] |  |  \- commons-codec:commons-codec:jar:1.4:compile
[INFO] |  +- commons-cli:commons-cli:jar:1.2:compile
[INFO] |  \- org.slf4j:jul-to-slf4j:jar:1.7.7:compile
[INFO] +- com.miglayout:miglayout-swing:jar:5.0:compile
[INFO] |  \- com.miglayout:miglayout-core:jar:5.0:compile
[INFO] \- org.slf4j:slf4j-log4j12:jar:1.7.7:compile

让您的整个项目登录到一个日志系统是一个非常好的主意,在您的情况下可能是 log4j。这简化了一切,并允许您使用一个配置文件等,而不是拥有多个配置等

Slf4j 是一个日志外观,您可能知道,因此您可以毫不费力地将它绑定到 log4j。项目 C 是一个稍微大一点(但不是无法解决)的问题。让我们从更容易的事情开始:

要将 slf4j 桥接到 log4j,您只需包含对 SLF4J LOG4J 12 绑定的依赖项:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.12</version>
</dependency>

这将允许 slf4j 使用 log4j,这意味着您的 log4j.xml 文件(或类似文件)将被使用,等等

提示(编辑,正如 Niklas P 在评论中提到的那样):您当然也可以从 SLF4j 登录到 JUL 而不是 log4j,这没问题,但是路由 log4j(从项目 D ) 到 JUL(并且还需要一个配置文件),所以我不会那样做。但这也是个人喜好的问题(我更喜欢 log4j(2))。如果你想这样做,你可以为 Slf4j 添加 jdk14 绑定,并尝试将你的 log4j 内容从项目 D 路由到 JUL,请参阅 this answer

您可能会收到警告,指出还有其他绑定(在这种情况下,slf4j 会随机使用一个)。您必须通过查看 "effective pom"(例如,Eclipse Maven 有一个选项卡)来排除其他绑定,然后从依赖项中排除这些绑定。例如,在我的一个项目中,我有这样的东西......

    <dependency>
        <groupId>org.zkoss.zk</groupId>
        <artifactId>zkspring-core</artifactId>
        <exclusions>
            <exclusion>
                <!-- Exclude logback binding for slf4j -->
                <artifactId>logback-classic</artifactId>
                <groupId>ch.qos.logback</groupId>
            </exclusion>
        </exclusions>
    <dependency>

您的类路径上应该始终只有一个绑定。在库的依赖项中包含绑定是一个非常糟糕的做法,因为这是应用程序应该决定的事情。请参阅 http://www.slf4j.org/codes.html

的 "Multiple Bindings" 部分

这将解决您的 slf4j/log4j 绑定问题。您的下一个问题是项目 C,它使用 JUL (java.util.logging).

您可以使用适配器将其桥接到 Log4j:

To use the JDK Logging Adapter, you must set the system property java.util.logging.manager to org.apache.logging.log4j.jul.LogManager

This must be done either through the command line (i.e., using the -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager argument) or by using System.setProperty() before any calls are made to LogManager or Logger. see https://logging.apache.org/log4j/2.0/log4j-jul/index.html

作为个人注意事项:由于 apache 已宣布 end of life for log4j 1.2,我建议考虑切换到 log4j2。

根据您的依赖关系树,您有多个 SLF4J 绑定。

[INFO] |  |     |  |  \- org.slf4j:slf4j-nop:jar:1.5.3:runtime
[INFO] |  |     |  +- org.slf4j:slf4j-jdk14:jar:1.5.6:runtime
[INFO] \- org.slf4j:slf4j-log4j12:jar:1.7.7:compile

如果是这种情况,您会在标准错误输出中找到与此类似的消息(请注意,这可能与标准输出不同,您实际上并没有看到 - 这取决于您执行应用程序的方式)。

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/frantisek/.m2/repository/org/slf4j/slf4j-nop/1.7.12/slf4j-nop-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/frantisek/.m2/repository/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.helpers.NOPLoggerFactory]

实际上,整个 maven-assembly-plugin 依赖项似乎并不正确,除非您正在开发 maven 插件。

[INFO] |  |  \- org.apache.maven.plugins:maven-assembly-plugin:jar:2.5.3:compile

要解决此问题,请排除 slf4j-nopslf4j-jdk14 或删除整个依赖关系。