Suppose there is an application, which uses log4j directly, i. e. without slf4j or any other wrapper. Now I would like to replace the log4j with logback. Should I use slf4j (or any other wrapper)? What is considered "good practice"?
You surely should use slf4j API, if you later decide to go back to log4j or something else you will only need to change slf4j bridge, and your application logging code will work without changes. Besides, if you visit http://www.slf4j.org/ you will see that slf4j considers Logback as its native implementation, Logback actually natively implements the SLF4J API.
As mentioned by Evgeniy Dorofeev, logback natively implements the slf4j-api. This means that invocation of a logback logger via the slf4j-api, that is via an instance of org.slf4j.Logger incurs no overhead at all. You could directly invoke loggers of type ch.qos.logback.classic.Logger instead of org.slf4j.Logger but doing so does not provide any advantages but will probably make it harder to migrate to a different logging framework if and when you chose to do so.
By the way, slf4j is not a wrapper for logback as logback is implemented in terms of the slf4j-api.
To ease migration to SLF4J, there is a tool for migrating source code to slf4j. For code which can not be modified by you, there are bridges for log4j, java.util.logging and commons-logging.
You may be able to migrate with no code changes at all, using the log4j-over-slf4j.jar instead of the "real" Log4J one. This provides the same API as Log4J to its clients, but directs the logging calls to SLF4J, which in turn can send them to logback.
But if you have the option of modifying the code then I would recommend changing it to use SLF4J, and you can then swap in any back-end as required (logback, log4j, etc). One thing you must not do is try and combine log4j-over-slf4j with the Log4J backend...
There is one very good reason for using the SLF4J api regardless of actual logging backend, namely the
log.debug("Foo: {}, Bar: {}", foo, bar);
parameter construct. Log4j always need a full string to log, which is why you need surrounding ifs to see if the statement is enabled for an expensive string. SLF4J do not call foo.toString() or bar.toString() before doing the check, so disabled calls are cheap.
Hence I would suggest migrating your source to slf4j and use the appropriate bridge in the slf4j download to use log4j as the backend. This will allow you to continue as you do now, without further changes. You can then switch backend to logback if you need to.
Related
So I have a large application using log4j. We are developing internally our own log implementation, that has nothing to do with log4j, but it conforms to the log4j API for logging. Therefore we just want to somehow swap log4j for our log implementation without changing anything in our code, in other words, it will continue to use the log4j API with our log implementation under-the-hood.
Has anyone done that or know how to go about doing that?
It would be easy if I was using SLF4J, but unfortunately I'm not.
Your best bet would be to write your custom logging framework as an slf4j implementation.
Then, remove log4j from the class path and drop in the log4j-over-slf4j bridge instead.
http://www.slf4j.org/legacy.html
The log4j-over-slf4j bridge will take any calls made to log4j and redirect through slf4j to whichever slf4j subsystem you're using on your classpath, which would in this case be your custom library.
I created a library using Java & Maven that contains some common Spring functionality for reuse in various Spring-Based projects.
The library will obviously need to log error/information messages. Spring allows the developer to use whichever logging library they prefer, how do I make my library do the same?
Spring uses commons-logging which is a logging facade that allows you to write logging code without knowing what is the actual logging framework.
Depending on what you have configured, the commons-logging will then channel the logging messages to the actual implementation. This allows you to write your code using commons-logging, and the users to use any logging framework supported by commons-logging.
Personally I would go with slf4j (Simple Logging Facade 4 Java) which is similar to commons-logging, but newer and functions in pretty much the same way.
It's also possible to bridge different libraries or facades, so that even if libraries use different logging frameworks they will always end up in the logger of your choice. Looking to the monitor to my right there are bridge libraries as follows: jcl-over-slf4j (commons-logging to slf4j), log4j-over-slf4j and jul-to-slf4j (java.util.logging to slf4j).
Note: See the link in comments for more information about how slf4j = good, JCL = bad ;)
Can I set the way log is written using Commons-logging instead of log4j?
I really want to use commin-logging due to the spec.
No, you can't. To quote from the documentation itself:
JCL provides only a bridge for writing log messages. It does not (and will not) support any sort of configuration API for the underlying logging system.
This is by design. The idea is to use a common logging API while being able to use any underlying log library that you want. You will still have to configure that underlying library.
Commons-logging is just a bridge between your application and the underlying logging system so as Joachim points out you cannot use it for configuration.
Also doesn't stop you using log4j, you still need an underlying logging implementation.
Also might want to look at slf4j as discussed here http://helpdesk.objects.com.au/java/which-logging-framework
I have this 3rd party library that has:
slf4j-api-1.5.5.jar
slf4j-jdk14-1.5.5.jar
jcl-over-slf4j-1.5.5.jar
I want to write some tests against this library and see its log output, and I don't want to add any more logging libraries (no log4j or anything else).
I understand that SLF4J and Common Logging are both logging abstractions so I probably need to write my own simple concrete logger (or maybe not, since jcl-over-slf4j includes org.apache.commons.logging.impl.SimpleLog?). If so, what interfaces should I implement, and more importantly, how do I set up SL4J/Common Logging to use my logger in my test? I read in the SLF4J docs that I have to modify the StaticLoggerBinder class... does that really mean that I actually have to download SLF4J sources, modify the class and recompile it?
We use SLF4J. It's very useful but several of the jars have confusing names and it's not real clear starting out to know which ones are incompatible.
SLF4J is the API you use for logging in your code (e.g. log.info("blah"). However, SLF4J has no configuration aspect to it. At runtime you add exactly one jar to the classpath that binds the API to the 'real' logging subsystem. If you want to use Log4J, add slf4j-log4j.jar or the StaticBinder jar for Simple or JDK, or Logback. You configure any of these logging implementations as you normally would without SLF4J.
There are several SLF4J modules available to redirect existing logging statements written using the APIs of Log4J, Apache Commons Logging, and java.util.logging to SLF4J. This allows you to setup a single logging configuration for all these disperate implementations. (This is very useful to avoid configuring both, say, Log4J and JUL if you have libraries that bind directly to any legacy logging framework.)
The SLF4J legacy page explains these concepts in depth. Heck, there is even a module to redirect Sysout.out/err to SFL4J.
To more directly answer your question: sure you can write your own logging implementation to go under SLF4J; but the only reason to do so is because you are already locked into some homegrown craptastic logging framework.
If you want to keep it simple, use the built-in (as of jdk 1.4) logger
https://docs.oracle.com/en/java/javase/19/docs/api/java.logging/java/util/logging/Logger.html
the jdk binding jar comes with slf4j. you want to make sure the jar is deployed to your webapp WEB-INF/lib dir or just in your classpath otherwise. See (slf4j.org/faq.html#where_is_binding) and this (slf4j.org/faq.html) for more information.
the jar you want to add to your classpath is slf4j-jdk14.jar. Note that the jdk logger is already available, this jar is the link between the slf4j interfaces and the chosen logger implementation. the jdk logging binding jar comes with the slf4j distribution. this should do it for you.
Your question leds me to believe that you have not read the the SLF4J user manual. It's a very short document. If after reading the document you still have the same question, then the document fails its purpose and needs to be clarified.
Anyways, you don't need to implement your own Logger class. Just use slf4j-simple which ships with SLF4J.
We are developing a web-based application in Java using the Spring framework. We are wondering which Logging system would be the most appropriate for it, whether Log4j or JUL (java.util.Logging), which is integrated with jdk. As far as I'm concerned, the former is more popular among developers and offers higher customization options, but I'm not sure which is simpler to adapt with spring.
any help will be appreciated.
thanks!
Before you start with log4j, look at logback. Log4j shouldn't be used for new projects anymore. If you have legacy code that needs any logging framework, use slf4j to make the old code talk to logback (or log4j if you must).
The main reasons you should not use JUL is that it implements the bare minimum that you need for logging, the configuration is hard at best and, if you use any component that doesn't use it, you'll have to deal with two logging frameworks.
Regardless of which logging framework you use in your own code, as far as I can remember, Spring has a hard dependency on commons-logging. You can still use whatever you like for your own logging (I'd recommend SLF4J as your facade, with logback as your implementation), but Spring internally needs commons-logging. Whether you want to depend on multiple frameworks is your choice; it shouldn't prove problematic.
Spring uses commons logging, which is a log abstraction facility but has issues that sl4j doesn't have. Hibernate moved to slf4j - I would like to see spring do the same, but I don't think they have any plans in this regard.
So as long as your log abstraction facility (use slf4j) logs to the same logging framework as you've configured commons logging in spring, then you're good. One log configuration for both. You might find an adapter for logback for commons and slf4j.
Since the other responses didn't actually answer your question, I thought I'd have a stab at it.
Firstly, java.util.logging is horrible. It's a pain to use, and a pain to configure. Log4J is nicer on both counts. However, you should pick whichever one you're most comfortable with. Spring uses commons-logging, which in turn will use either log4j (if found on the classpath) or java.util.logging otherwise. In otherwords, if your application already has log4j present, then Spring will effectively use that, and so should you. If log4j is not already present, then either use java.util.logging (if you choose to), or add log4j to your classpath and use that.