I am trying to using slf4j and log4j together. After some googling, I found some solutions:
How does simply adding slf4j to the pom.xml wrap log4j?
https://dzone.com/articles/adding-slf4j-your-maven
How to get SLF4J "Hello World" working with log4j?
Various names and versions of jars related to slf4j and log4j just confused me so much. slf4j-log4j12, log4j, log4j-core, log4j-over-slf4j, log4j-slf4j-impl, log4j-api, slf4j-impl, log4j12-api, log4j-to-slf4j ...... I can't even know the function of these different jars.
So, which combination and version should I choose?
The standard way to use SLF4J is that it's the main logging framework that you use. (You call methods defined within the slf4j-api.) It, in turn, uses a "binding" such as slf4j-log4j12 which tells it how to talk to the "real" logging framework. And then you also need to have the real logging framework on your classpath, such as "log4j" version 1.2.
Some newer logging libraries, such as Logback, are both the "binding" and the "real" framework, so if you want to use that as your logging framework, you only need logback-classic along with slf4j-api, so it's two libraries rather than three.
The confusing "over" and "to" libraries exist as a way to deal with the reality that you probably depend on libraries that want to log in a different way than the way you've selected for your application, but it's nice to have everything directed into one framework. So, if you're using SLF4J and Logback, but you're depending on a library which logs using Log4j 1.2, you want to include the log4j-over-slf4j library, which will "intercept" any Log4j calls within any libraries in your application and translate them to be logged by SLF4J instead. Conversely, if you're logging with Log4j 1.2 directly (without SLF4J) and need to call a library that's using SLF4J, you're going to want to include the slf4j-log4j12 library to intercept those calls and translate them to Log4j for you. There are a variety of these kinds of libraries, each to intercept and translate from one particular logging framework to another.
But your question was "So, which combination and version should I choose?", which is rather broad, as we're not sure what it is that you're trying to do. Selecting a logging framework is like any other technology framework decision, based on a lot of things like developer familiarity, what the systems you need to integrate with are using, and if there are any existing code or standards which one wants to stay consistent with. So, I'm going to try to avoid getting into that selection process too much, and answer your question about how to set up Maven to use SLF4J as your logging framework, backed by Log4j version 2:
Add a dependency for the current version of slf4j-api
Add a dependency for Log4j 2 and its SLF4J binding (From https://logging.apache.org/log4j/2.x/maven-artifacts.html):
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.6.1</version>
</dependency>
</dependencies>
Use <dependencyManagement> sections in your POM to ensure that all your dependencies use the same version of your logging framework. (For instance, many libraries will include slf4j-api as a dependency, but they may each use a different version.) Generally logging frameworks keep good compatibility between versions, so you generally want to override all the supplied dependency versions with the (usually newer) one that you're using.
If you have any libraries that are using other logging framework, use the appropriate interceptor bridge to redirect its logging, either one from Log4j 2 that will redirect it straight to Log4Jj 2, or one from SLF4J which will redirect to SLF4J, which will then be further directed to Log4j. (While it may seem to do redirect twice, it could make things easier if you were to keep SLF4J but change to another "real" logging framework at some point. Maybe.) For instance, if you have a library that uses commons-logging, you want to include jcl-over-slf4j instead.
Also, use the maven-enforcer-plugin's bannedDependencies rules to ensure that you're excluding any logging frameworks that you're not using that the libraries you're depending on are trying to bring into your project. That is, for that example I gave of a library you depend on that uses commons-logging, you need to <exclude> commons-logging from that library dependency, and add it to your bannedDependencies list to ensure that you don't accidentally get it again from some other library. Otherwise, you'll have both the "real" commons-logging as well as your fake bridge (that emulates the interface and translates to your real logging framework) on the classpath, and will run into trouble.
I hope that overview helps. Note I haven't actually tried running Log4j 2 in anything yet, and just got those dependencies from their documentation. Definitely test that everything's working the way you expect.
Related
Think to Simple Logging Facade (SLF4J) for Java. As a background, it provides an API by means of a simple facade pattern in a way that the underlying logging backend is determined at runtime by adding the desired binding to the classpath. It may be the standard java.util.logging, log4j, logback or tinylog.
The neat separation of the client application from the logging backend reduces the coupling between the specific application and any particular logging framework. This can make it easier to integrate a newly implemented client with existing code of other projects that have already made a choice of logging backend.
So considering the logging API SLF4J, for compilation you need only the slf4j-api and you shall avoid including any specific binding like slf4j-log4j12 as a compile dependency.
As result, slf4j-log4j12 is a good candidate for being a runtime scoped dependency instead of a compile dependency, because this will allow you to switch among slf4j bindings at runtime without having to recompile the application.
Question: where to set the switching among logging frameworks bindings at runtime in a Maven project? Any example?
Disclaimer: I am the author of SLF4J
Even though the documentation talks about changing the logging back-end at runtime, SLF4J allows to switch logging back-ends at build time but not at runtime.
I inherited a web service that used to work fine until we had to upgrade the runtime environment (from JBOSS/JRE6 to Tomcat7/JRE7). There was no code change except for the pom.xml!
In fact it still works fine, except that the many existing clients can no longer handle the response because of an extra namespace attribute now present in one of the elements (of the response).
That is, previously (before the migration) that element (in the SOAP response) used to be:
<OurResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="OurResponse.xsdXMLSchema-instance"
ourresponseVersion="M1m2v03" xmlns="">
And now it is:
<v01:OurResponse acknowledgementVersion="M1m2v03"
xmlns:v01="http://webservice.ourdomain.com/projone/modtwo/M1m2v03">
Since there was no code change involved, I am baffled by this (minor but critical) change in the SOAP response.
In particular, I am trying to understand:
Which part of the build system changes this namespace attribute?
How do I restore it back to previous behavior?
Why would the clients break on such a minor change? (i.e. the content of the response is identical!)
The only relevant changes I have been able to spot in the pom.xml are:
Adding the following dependencies:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.0.7.RELEASE</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
</exclusions>
</dependency>
Updating the cxf-rt-frontend-jaxws dependency from version 2.2.7 to 2.7.7.
Updating the cxf-rt-transports-http dependency from version 2.2.7 to 2.7.7.
Updating the cxf-rt-ws-security dependency from version 2.2.7 to 2.7.7.
Adding the following dependencies:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-core</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-databinding-aegis</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-management</artifactId>
<version>2.7.7</version>
</dependency>
Again, I am assuming there is some internal change in one of the frameworks involved (CXF? Spring?) that handles this internally. If this assumption is correct, then:
Which part of the build system changes this namespace attribute?
How do I restore it back to previous behavior?
Why would the clients break on such a minor change? (i.e. the content of the response is identical!)
Update 1:
The culprit turned out to be the org.apache.cxf packages version change from 2.2.7 to 2.7.7.
Looks like newer is not always better... unless there is a way to programmatically to force the legacy behavior of stripping out the namespace prefixes?
Update 2: Using CXF 2.2.7 on Tomcat7/JRE7 had the side-effect of killing the Tomcat server after sending a single SOAP message (seems to be related to SSL).
The fact that a venerable server like Tomcat can die due to a single rogue .war package is pretty disturbing but since I cannot fix Tomcat and I have not found a programmatic way to workaround the implicit namespace prefix issue, I tried various stable CXF releases that would exhibit the legacy behavior without killing Tomcat.
I tried versions 2.7.1 and 2.6.10 but eventually only 2.5.9 worked.
I hope this helps someone who stumbles on a similar problem.
Conforming XML implementation are not permitted to die due to changes in the use of xmlns attributes. Expressing the same data model with a prefix or without, it's the same thing. If your client failed, you need to fix the client. If you have clients that are hypersensitive to the use of namespace prefixes instead of to the real data model, CXF is not necessarily a good choice.
Most likely CXF upgraded to a more recent version of JAX-B, and it changed its mind about the namespace prefixes.
To elaborate this: Apache CXF was designed to focus on standard-conforming web services. Apache Axis has traditionally filled the space for not-so-standard-conforming web services, just fine. So no, the CXF development community has never worried about 'prefix stability'. If the XML is formally correct, CXF tests are happy.
For this, and many other reasons, CXF delegates XML generation for JAX-B web services to the official JAX-B reference implementation. New versions of CXF pick up new versions of JAX-B. JAX-B, from time to time, makes changes that have the effect of rearranging the namespace prefixes.
The XML generation in CXF is pluggable, so if you want to use an older JAX-B, or roll your own, you can. You can provide a 'Provider' and do the whole job yourself if you like.
There is an option in CXF to pass an object into JAX-B that decides what prefix to use for what namespace, but I don't think that it can be used to force a particular namespace to be defaulted. You might be able to get what you want with a Provider and a carefully configured call to the JAX-B API.
The CXF User mailing list archive has hundreds of messages to and from people who are swimming upstream with namespace prefixes.
(As for tomcat dying, well, that's another question.)
When we run a sample main program which reads a applicationContext.xml with a single bean..
how does Spring do the logging..and how can one overwrite the default logging.
I didnt see any log4j.xml in the spring dependencies as well..
Regards
This is described in the documentation:
Logging is a very important dependency for Spring because a) it is the only mandatory external dependency, b) everyone likes to see some output from the tools they are using, and c) Spring integrates with lots of other tools all of which have also made a choice of logging dependency. One of the goals of an application developer is often to have unified logging configured in a central place for the whole application, including all external components. This is more difficult than it might have been since there are so many choices of logging framework.
The mandatory logging dependency in Spring is the Jakarta Commons Logging API (JCL). We compile against JCL and we also make JCL Log objects visible for classes that extend the Spring Framework. It's important to users that all versions of Spring use the same logging library: migration is easy because backwards compatibility is preserved even with applications that extend Spring. The way we do this is to make one of the modules in Spring depend explicitly on commons-logging (the canonical implementation of JCL), and then make all the other modules depend on that at compile time. If you are using Maven for example, and wondering where you picked up the dependency on commons-logging, then it is from Spring and specifically from the central module called spring-core.
The nice thing about commons-logging is that you don't need anything else to make your application work. It has a runtime discovery algorithm that looks for other logging frameworks in well known places on the classpath and uses one that it thinks is appropriate (or you can tell it which one if you need to). If nothing else is available you get pretty nice looking logs just from the JDK (java.util.logging or JUL for short). You should find that your Spring application works and logs happily to the console out of the box in most situations, and that's important.
(emphasis mine)
Follow several sections describing how to use various logging frameworks.
I am developing a simple web application, using Spring Framework.
When I add Spring framework to my class path, I see that it has lot of jars which I never use (for example: spring-aop-3.2.3.RELEASE.jar).
Is it a good idea to keep the entire framework intact or remove unused jars?
If you need to remove unused jars, the best way is to use some dependency management tool like Ivy or Maven, and let the tool decide what the required dependencies are. Otherwise it will not be apparent what is really unused or not until you break something.
For instance, if you are using declarative transactions, then removing the AOP jar will cause breakage, because AOP is used to implement that functionality.
If you would rather not use dependency management, it's better to leave everything intact.
There are some cases where you do want to remove/exclude jars. Replacing commons-logging with slf4j is one example. Another example is excluding the log4j dependencies that get dragged in on account of some appender that's packaged with log4j but that you know you will never use. Dependency management tools allow you to tell them what needs to be excluded.
Doing without dependency management management and removing things because you never use them directly is too dangerous.
I would like to use SpringLDAP to do some simple username/password verification for authentication purposes. WHile the actual jar file is quite small (less than 1 meg) it seems to have a lot of dependencies as listed by link text.
By alot i mean it seems to suck in over 50 things many which dont seem right such as spring-jdbc as I dont want any jdbc and only the ldap template class and its bare dependencies. Without wasting too much time is it possible to the spring-ldap with only a bare minimum number of dependencies which amount to something like:
spring core
spring ldap
whatever logging deps they require.
spring tx
I dont see or appreciate why the rest of thes tuff is reuqired and was wondering can anyone verify they arent really needed in the end if one sticks to the basics. The other stuff i am referring too include:
spring-orm // no jdbc
beans // i dont want ioc.
spring-aop // no need for aop.
I intend to wire up the beans i will be using manually. I dont want more crap in there for what ammounts to setting a few properties, and want confirmation that I dont need what is probably there just to do the ioc stuff when all i want is the ldap stuff.
At lot of the things that are sucked in are transitive dependencies - dependencies of the things that spring-ldap relies upon. You can explicity exclude these when declaring your dependencies using the exclusions tag in the dependency.
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap</artifactId>
<version>1.3.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</exclusion>
<!-- other exclusions here -->
</exclusions>
</dependency>