Java slf4j implementation: logback vs log4j - java

I received a project done by another developer (whom I cannot get in touch with right now). In that project, slf4j is used for logging. But I see log4j-1.2.17.jar along with logback-access-1.0.9.jar,logback-classic-1.0.9.jar,logback-core-1.0.9.jar in the classpath. Also both log4j.properties and logback.xml files are in the resources. Now I am confused which implementation is actually used. Can anyone suggest anything?
Update
There is also slf4j-api-1.7.2.jar and slf4j-log4j12-1.7.2.jar in classpath

If you don't see slf4j-api.jar in the class path then, as mentioned below, SLF4J will default to a no-operation implementation. It seems like the other developer was using SLF4J to plug in log4j-1.2.17.jar(log4j) along with logback-access-1.0.9.jar , logback-classic-1.0.9.jar and logback-core-1.0.9.jar(logback) at deployment time.
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.
Before you start using SLF4J, we highly recommend that you read the two-page SLF4J user manual.
Note that SLF4J-enabling your library implies the addition of only a single mandatory dependency, namely slf4j-api.jar. If no binding is found on the class path, then SLF4J will default to a no-operation implementation.
- From SLF4J - Simple Logging Facade for Java

Related

How to get slf4j console output when no implementation is present?

We have many "parent" (or "library") projects. They only have the slf4j-api in the classpath, but no implementation like logback.
I often want to write a quick temporary main method to test something, and get
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
How can I get output without adding a logging implementation dependency?
You can't get around having some logging dependency available if you want log output. What you can do, however, is to use the simple binding and set the dependency as <optional>true</optional>. This effectively prevents the dependency from being added transitively to client projects while making it available when you run a main method in that specific module.
Slf4j provides APIs (interfaces), not an implementation, so without adding some implementation / rolling your own IMO it would be impossible to see something being actually printed on console and in general to get around this warning an make it work in a way you ask.
If you don't need a logback, you can use slf4j simple binding for example.
Another option is to use some kind of bridge to adapt the slf4j apis to Java Util logging and then there is an implementation in JDK (like slf4j-jdk14-1.8.0-beta4.jar)
If you want tests you can use the dependency in scope "test" (assuming you use maven, for example) so it won't propagate to the artifact.
To your question, "How can I get output without adding a logging implementation dependency?". It is not possible in SLF4J. There has to be one logging implementation. If I go by the Bible of SLF4J, it says "The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time".
As Mark mentioned, you can use .jdk14.jar file to eliminate the warning and to print. But in case of any library, you have to add it.
For more reference, you can check below.
https://www.slf4j.org/
https://www.slf4j.org/manual.html

route slf4j to log4j, not the opposite

It is well known how to adapt code that uses log4j to slf4j and have the latter as main logger, including plugging implementations like LogBack as concrete application logger.
What about the opposite route? I have a large application that is using log4j everywhere, migrating it to slf4j would be very difficult, for instance I have many command line tools all having their own log4j config file.
Now I have to extend the application by using a small library that is sending log messages to the slf4j interface.
Is there a way to re-route all slf4j calls to the already existing log4j, so that, for example, I could rely on the existing application configuration to tune the logging behaviour of the new library too?
Is there a way to re-route all slf4j calls to the already existing log4j?
slf4j-log4j12 module will serve your purpose. More about this module here.
Overall, you will need:
log4j (latest 1.2.17): for existing dependencies and re-routing
slf4j-api (latest 1.7.25): for new slf4j dependent libraries
slf4j-log4j12 (latest 1.7.25): for re-routing

How to set up a common logging framework

I have written a small java application. The application uses some external packages as cling, javax and weld.
In my code I used java.util.logging but the other packages uses other loggers as sl4j.
Question. Is there a way to take control over the logging environment so all packages logging in a simular way. I would like to have a simple way to change loglevel and log output.
//lg
slf4j is a logging facade behind which different logging frameworks can be used. For example log4j. You just have to throw it in the path. Log4j can then be configured as usual. There should also be a jul bridge if you want to stick with java.util.logging.

What logging system I use?

How to determine, what logging system given project uses?
It has signs of log4j, slf4jand logback. Looks like active config file is log4j.properties. The loggers are created in classes by
private static Logger log = LoggerFactory.getLogger(MyClass.class);
the full type of logger is org.slf4j.Logger and the type of factory is org.slf4j.LoggerFactory.
But there are also jars logback-core-0.9.26.jar and logback-classic-0.9.26.jar.
Other jars are slf4j-log4j12-1.6.1.jar, slf4j-api-1.6.1.jar, log4j-1.2.16.jar and commons-logging-1.1.1.jar.
What defines that logback is apparently inactive? How to activate it?
sl4j is a facade, there is no actual implementation. In other words sl4j cannot work alone, underlying logging framework can be log4j, logback, java util logging and so on.
slf4j-log4j12-1.6.1.jar dependency implies that the underlying logging implementation is log4j.
Advantage of this approach is that later on you can switch your logging implementation from Log4j to logback(which is claimed to be better by many) or any other logging framework. Your classes are not tightly coupled to logging framework.
Given the jars you mentioned, I assume the logging system is log4j, accessed through either slf4j or commons logging (maybe provided to satisfy other frameworks' dependencies).
The key here is slf4j-log4j12-1.6.1.jar which instradates slf4j through log4j.
If project code uses slf4j, then asking what logging system it uses is asking a wrong question, in a way. It will use whatever logging framework slf4j finds at runtime. If you are unsure, turn on debugging information on all the relevant libraries:
For log4j, add -Dlog4j.debug to java command line.
For slf4j I remember adding debug code and there printing the class name of ILoggerFactory instance (returned by LoggerFactory.getILoggerFactory()), which reveals what actual logger it will use.
Not sure how to debug logback or commons logging, but I'm sure their docs tell that.
The situation you describe where both logback-classic.jar and slf4j-log4j12.jar are present on the class path is an instance of the "multiple-bindings problem" mentioned in the SLF4J error code documentation. The explication for the relevant error code states:
The warning emitted by SLF4J is just that, a warning. Even when
multiple bindings are present, SLF4J will pick one logging
framework/implementation and bind with it. The way SLF4J picks a
binding is determined by the JVM and for all practical purposes should
be considered random. As of version 1.6.6, SLF4J will name the
framework/implementation class it is actually bound to.
Strangely enough you did not mention this error message in your question. If as you say both logback-classic.jar and slf4j-log4j12.jar are really present on the class path, then SLF4J will definitely print "Multiple bindings were found on the class path" as a warning. If it does not, then only one binding is actually present on the class path.

Baffled by Java Logging Systems with Spring and Hibernate

WHen deploying my Spring / Hibernate application, I get the following warning related to logging:
log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.
Surprising to me was the lack of information from a Google / SO search. The only thing relevant was this SO post Problem with Commons Logging / Log4j setup in spring webapp with tomcat 6
However, this is even beyond me. Can somebody clarify the logging systems in play here, or point me to a RECENT resource on the matter (there are some ancient google search results that don't really apply). Specifically, the issues I'm wrestling with are:
The distinction among commons-logging, log4j, slf4j and JCL. My understanding is that slf4j is a wrapper, while commons-logging and log4j are actual implementations. I don't know where JCL fits in.
How to configure logging for Spring. What does in the web.xml file, do i need a log4j.properties file or a log4j.xml file? Where does it go, in WEB-INF? Does anything go in my applicationContext.xml file? (sorry but I need to start from zero here).
I am using Hibernate in my project and including via Maven. It seems that Hibernate uses slf4j-simple. I have seen warnings saying that I can't have slf4j-simple and slf4j-log4j both on the classpath. I have not included slf4j-log4j as a dependency, but Hibernate must be including it. How do i solve this problem? Can I force Hibernate to use log4j instead?
Any help would be greatly appreciated. Thanks.
edit:
Thanks for all the answers so far. I am giving these suggestions a try. What about spring web-app specifically? I've seen examples of listeners and parameters and whatnot put into the web.xml file. Is this also required?
commons-logging and SLF4J are both API wrappers around other logging implementations. SLF4J is the more modern of the two, and rather more capable. Log4j is a logging implementation, and pretty much the defacto standard. JUL (short for java.util.logging) is the (generally awful) logging implementation that comes with the JRE. Another log implementation is logback, which is slowly gaining traction, but not at all widespread yet.
log4j.properties and log4j.xml are different ways of configuring log4j, both are equally valid. Which one you use is up to you, although some application servers dictate one or the other. Read the log4j manual to find out how to configure this.
If Hibernate uses SLF4J as its API, that's the choice of the Hibernate developers. However, you can choose which logging implementation SLF4J will delegate to. Again, read the slf4j manual to find out how to select your chosen implementation.
Yes, it's all rather confusing. Given an open choice, SLF4J and Logback is the most capable combination, but you usually don't get an open choice. Different frameworks (like Hibernate and Spring) will potentially use different logging APIs, usually commons-logging or SLF4J, but you can get all those APIs to eventually log to the same underlying implementation (usually log4j).
The distinction among commons-logging, log4j, slf4j and JCL. My understanding is that slf4j is a wrapper, while commons-logging and log4j are actual implementations. I don't know where JCL fits in.
Jakarta Commons Logging (JCL) and Simple Logging Facade for Java SLF4J are both abstractions for various logging frameworks e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time. Commons Logging is known to suffers from class loader problems which is what SLF4J tries to solve (SLF4J is known to be a cleaner library).
Having that said, the fact is that Spring uses Jakarta Commons Logging API (see Logging Dependencies in Spring): Spring is compiled against JCL and Spring makes JCL Log objects available for classes that extend Spring. The is actually the only mandatory external dependency in Spring. This choice has been made because many other frameworks where also using it (e.g. Struts). The idea was to avoid having to have multiple facade libraries on the class path when building applications ("A" for Spring, "B" for Struts, etc). It is however possible to replace JCL by SLF4J if you want to (SFL4J provides bindings to logging frameworks but also a "JCL to SLF4J" bridge). See the mentioned post Logging Dependencies in Spring for all the details.
How to configure logging for Spring. What does in the web.xml file, do i need a log4j.properties file or a log4j.xml file? Where does it go, in WEB-INF? Does anything go in my applicationContext.xml file? (sorry but I need to start from zero here).
To log, you have 1. to decide which implementation you want to use (java.util.logging, log4j or logback), 2. to put the chosen one on the classpath if required (java.util.logging is in Java SE so it doesn't require extra libraries) and 3. to configure it (by putting a config file on the classpath). If you choose to use log4j, just add its jar and a log4j.properties or a more fancy (but more verbose) log4j.xml (this is just another format for the configuration) to the classpath.
I am using Hibernate in my project and including via Maven. It seems that Hibernate uses slf4j-simple. I have seen warnings saying that I can't have slf4j-simple and slf4j-log4j both on the classpath. I have not included slf4j-log4j as a dependency, but Hibernate must be including it. How do i solve this problem? Can I force Hibernate to use log4j instead?
Hibernate utilizes Simple Logging Facade for Java (SLF4J) and, indeed, you can't have several bindings (e.g. slf4j-simple.jar and slf4j-logj12.jar) on the classpath at the same time. Here, you are very likely getting slf4j-simple.jar transitively from another dependency. To solve this problem, run mvn dependency:tree to figure out from where it's coming from and exclude it if required.
And by the way, in your case, I would configure Spring to use SLF4J as Hibernate is using it. Follow the steps in the link mentioned in the first paragraph for that. And I would use logback as logging framework (which the successor of log4j), this is where things happen now.
You need a log4j.properties file in your classpath. Here is a minimal properties file I happened to have created yesterday:
log4j.logger.BillReview=INFO,BillReviewLog
log4j.appender.BillReviewLog=org.apache.log4j.RollingFileAppender
log4j.appender.BillReviewLog.File=BillReview.log
log4j.appender.BillReviewLog.Append=true
log4j.appender.BillReviewLog.MaxFileSize=5000KB
log4j.appender.BillReviewLog.MaxBackupIndex=5
log4j.appender.BillReviewLog.layout=org.apache.log4j.PatternLayout
log4j.appender.BillReviewLog.layout.ConversionPattern=%c %p %-10.10X{server} %-4.4X{user} %d{ISO8601} %m%n
Put that into a log4j.properties file, change all the references to 'BillReview' to something more like your project and that'll log to a file and stop those messages.
Your questions about which logging framework are largely personal choice. Log4j is the old standard and it works fine, Commons logging and slf4j are newer APIs and allow some more complicated use cases.
I'll let some more experienced Gurus than I answer the first bullet.
Answering your second bullet...
You can use either a log4j.properties or log4j.xml file (it doesn't matter which). Whatever you choose you should add it to your classpath (typically it should go in the same directory as your source code). If you are using Spring, a nice way to break your src directory up into logical portions is by using the following directory structure...
src/main/java -- put main source here
src/main/resources -- put resources used by you main source here
src/test/java -- put test source here (for tests)
src/test/resources -- put resources for tests here
You would therefore put your log4j.properties in the src/test/resources directory.
Answering your third bullet...
You can exclude a dependency within a dependency in you pom.xml file by doing the following...
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>${xbean.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
I had problems in the same area while running my tests. I eventually noticed that junit was bringing in slf4j-nop as a dependency, in addition to the slf4j-log4j12 that I wanted. Once I excluded slf4j-nop, it started working.

Categories