简体   繁体   中英

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

So I have 4 Maven projects, let's call them A, B, C and D. Project A depends on project B depends on project C and project A depends on project D too.

D
^
|
A -> B -> C

Project A and B use slf4j
Project C uses java.util.logging
Project D uses log4j

Now I do not really know how to set up it's logging dependencies to get it working.

What I have is:
Project D depends on log4j and nothing else.
Project C depends on nothing because it just uses java's logging utility.
Project B depends on slf4j-api as well as jul-to-slf4j to also log what C logs
Project A depends on slf4j-api , slf4j-log4j12 and log4j

Project A is the main program which I want to run. It has a log4j.properties file set up for logging to console.

# 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

The problem now is, that when I start the program all slf4j logs will get ignored. I tried to log something using a log4j-Logger in Project A and that gets logged.

Project A's dependency tree:

[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

Based on your dependency tree you have multiple SLF4J bindings.

[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

You would find message similar to this on standard error output if that is the case (beware that this might be different from standard output and you are not actually seeing this - this depends on how you execute your app).

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]

Actually the whole maven-assembly-plugin dependency doesn't seem right, unless you are developing a maven plugin.

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

To solve this either exclude slf4j-nop and slf4j-jdk14 or remove whole dependency.

It's a really good idea to get your whole project logging into ONE logging system, in your case that would probably be log4j. This streamlines everything and allows you to use one config file, etc. instead of having multiple configurations, etc.

Slf4j is a logging facade, as you probably know, so you can bind it to log4j without much trouble. A slightly bigger problem (but not unsolvable) will be project C. Let's start with the easier stuff:

To bridge slf4j to log4j you only have to include a dependency to the SLF4J LOG4J 12 Binding:

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

This will allow slf4j to use log4j, which means your log4j.xml file (or similar) will be used, etc.

Hint (Edited in, as Niklas P mentioned it in a comment): You CAN of course also log to JUL instead of log4j from SLF4j, no problem there, but it's slightly trickier to route the log4j (from project D) to JUL (and requires one more config file), so I wouldn't go that way. But that is also a question of personal preference (I prefer log4j(2)). If you want to do that, you can add the jdk14 binding for Slf4j instead and try routing your log4j stuff from project D to JUL, see this answer for that.

You perhaps might get warnings that there are other bindings (in which case slf4j will use one pretty much randomly). You must exclude the other ones then by looking at the "effective pom" (Eclipse Maven has a tab for that, for example) and then exclude these bindings from the dependencies. For example, in one of my project, I have something like this...

    <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>

You should always only have exactly ONE binding on your classpath. It's a really bad practice to include a binding in your library's dependencies, because that's something the application should decide. See the "Multiple Bindings" section of http://www.slf4j.org/codes.html

This will take care of your slf4j/log4j binding problem. Your next problem is project C, which uses JUL (java.util.logging).

You can bridge that to Log4j by using the adapter:

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 (ie, 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

And as a personal note: As apache has announced the end of life for log4j 1.2, I suggest thinking about switching to log4j2.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM