How to change slf4j level at runtime? - java

I've using SLF4j as my logging framework, backed by log4j. My problem is that I am looking for a way to change the logging level for my logger at runtime.
I understand that slf4j does not permit this directly through its own API, and hence, I have to access the logging provider directly. Personally, I find this to be a huge deficiency in slf4j. So now my question is how can I determine programatically through slf4j which provider I am using? The biggest purpose of using slf4j is that you become provider agnostic - you can easily switch between your favourite logging system without having to recode anything. But now, if I have to make direct calls to log4j, I am losing that ability.
At the very least, I would like to be able to determine if I am using log4j as the provider and if so, then allow the user to switch log levels.
If I do LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME), the result is an instance of org.slf4j.impl.Log4jLoggerAdapter and not even org.apache.log4j.Logger (as I would have hoped/expected).
Is there any way to find this out?
Thanks,
Eric

SLF4J is designed as an abstraction for libraries, not applications (of course, you can and should still use SLF4J in your own app's logging calls, for consistency). In your own app, you choose the underlying logger framework, so it's fine to access the log4j API in the logging-config-specific parts.
No way should a library be mucking about with changing the logging config, IMHO, so it's not appropriate for it to be on the SLF4J API.

Related

Logback native VS Logback via SLF4J

I have gone through the following article regarding the logging frameworks available for Java:
http://michaelandrews.typepad.com/the_technical_times/2011/04/java-logging-reconsidered.html
The author has mentioned using SLF4J with Logback. How is that different from using Logback directly. Wouldn't it be better if one uses Logback directly rather than going for SLF4J, since Logback is built on top of SLF4J.
SLF4J is adding zero overhead to Logback since it is simply the interface that is implemented by Logback without any additional layer.
You should use SLF4J simply because...
It enables you to switch away from Logback if you ever need to
It does not cost you anything, even the imports are smaller ;)
Other people will love you for using SLF4J and hate you for using a specific logging framework directly if you ever release your code into the wild.
The only place where you'd access Logback directly would be while (re)configuring your logging manually in an application. The need for this arises occasionally but even in that case, working with Logback would be restricted to a single class or even method.
As a rule of thumb: libraries should always use a logging abstraction while applications define the logging they are using, optionally accessing it directly.
SLF4J adds almost no overhead and Logback has a native bindings to it.
If you know by 100% that you will not need to switch to other logging framework in the future, go with logback native. But SLF4J allows you some abstraction and you can switch logging backends in a blink.
Logback is not build on top of SLF4J. SLF4J is an abstraction framework for logging. It doesn't do any logging itself. It just provides unified interface for logging.

How to decouple logging implementation and API?

I'm creating a small Java framework, which will log its events. I don't want the framework to be dependent on any particular logging implementation (jul, commons logging, log4j, slf4j, logback, etc). Instead, I want to allow my clients to choose anything they prefer.
The question is - how should I realize such decoupling? How my framework should log its events?
slf4j is designed to solve exactly this problem: it decouples the API from the logging implementation.
slf4j is not a logging implementation by itself. It depends on the existence of a back-end implementation. Logback just happens to natively implement the slf4j API but there are bindings for log4j, java.util.Logging and others.
At some level you must have an API for your clients to use. You might as well make it one of the existing APIs rather than writing your own.
I think that will be difficult to achieve as your code must call something in order to log information and error messages. I think you will have to choose one (I recommend slf4j) and stick to it - this seems to be what is generally done by everyone else.
I would include support for AspectJ and Commons Logging.

What is the issue with the runtime discovery algorithm of Apache Commons Logging

Dave Syer (SpringSource) writes in his blog:
Unfortunately, the worst thing about commons-logging, and what has made it unpopular with new tools, is also the runtime discovery algorithm.
Why? What is the issue with its runtime discovery algorithm? Performance?
Why? What is the issue with its runtime discovery algorithm? Performance?
No, it's not performance, it's classloader pain. JCL discovery process relies on classloader hacks to find the logging framework at runtime but this mechanism leads to numerous problems including unexpected behavior, hard to debug classloading problems resulting in increased complexity. This is nicely captured by Ceki (the author of Log4J, SLF4J and Logback) in Think again before adopting the commons-logging API (which also mentions memory leaks problems observed with JCL).
And this is why SLF4J, which uses static bindings, has been created.
Ceki being the author of SLF4J, you might think his articles are biased but, believe me, they are not and he is providing lots of references (evidences) to prove his point.
To sum up:
Yes, JCL is known to be broken, better stay away from it.
If you want to use a logging facade (not all projects need that), use SLF4J.
SLF4J provides a JCL-to-SLF4J bridge for frameworks still using JCL like Spring :(
I find Logback, Log4J's successor, to be a superior logging implementation.
Logback natively implements the SLF4J API. This means that if you are using Logback, you are actually using the SLF4J API.
See also
Commons Logging was my fault
Think again before adopting the commons-logging API
SLF4J Vs JCL / Dynamic Binding Vs Static Binding
Commons logging is a light weight logging facade which is placed on top of the heavy weight logging API be that log4j, java.util.logging or another supported logging API.
The discovery algorithm is what commons logging uses to determine what logging API you use at runtime so it can direct log calls through its API to the underlying logging API. The benefit of this is that if you wanted to create a library that does logging, you do not want to tie down users of your library to any particular heavy weight logging system. Callers of your code can configure logging via log4j, java.util.logging etc. and commons logging will forward to that API at runtime.
Common gripes for commons logging:
Even though you don't use it, a library you depend on might so you have to include it in your classpath anyway.
Runs the discovery algorithm for each classloader you want to do logging in, which can produce unwanted results so make sure you put commons-logging.jar in the right classloader.
Greater complexity than the underlying logging framework.
Less features that underlying logging framework.
A perceived greater complexity as well as unpredictability in complex classpath hierarchies without any perceived benefits make users of commons-logging agitated. Given also that this choice may be forced on you does not make users sympathetic. See this article for a compelling argument against using commons-logging.
I can't speak about the "believed unpopular" aspect, I can only speak for myself:
Commons Logging is a facade over top of whatever your "real" logging framework may be: Log4j, Logback or whatever.
The idea of a logging facade is that your app gains the flexibility to decide at runtime which logging implementation it wants to work with. The facades are clever enough to find logging implementations at runtime.
My older Java apps use Log4j, directly. Works fine, I see no need to change them. My newer Java apps will probably use Logback. I think the ability to dynamically choose a logging framework is something none of my apps will ever need. Of course, other peoples' mileage may vary.
EDIT: Looks like I was wrong about the rationale for Commons Logging. The links given by #Pascal Thivent, especially the first one, explain this far better.
Commons Logging contains logic to determine at runtime whether to use log4j or java.util.logging.*.
That code used to be seriously broken, essentially only working with JUL.
Based on the experiences with this, slf4j was written which uses static binding (or used to, Im not sure with version 1.6) to choose the appropriate framework to use of log4j, JUL or the log4j fork logback (and more), and it includes a bridge to allow existing Commons Logging code to use slf4j transparently.
If you can, then go for slf4j.

Difference in using java.util.logging and Log4j Loggers

I am developing a java application for which i have to use a logging mechanism. And now i am confused to choose either java libraries logger or to go for Log4j logger.
So i want to know when i can go for java logger
and when i can go for log4j logger.
I'd suggest you go with SLF4J instead to decouple your application from specific logging frameworks. It has adapters for various popular logging frameworks such as Jakarta Logging, JDK1.4 logging, log4j etc. making it a good abstraction for logging needs.
Logger class was not part of jdk earlier on, so several library implementations sprung up. The Log4j library has one of the most comprehensive set of logging utilities (Formatters, Appenders etc). However, for most developers this would be an overkill and the simple java.util.Logger would suffice.
I personally use a custom wrapper over my logger implementation. This enables me to define custom calls to carry out functional logging/auditing.
There are the Apache Commoms Logging project and SLF4J, either of which abstracts the underlying logging library.
In practice I tend to use Log4J over the built in logging classes. Mainly because Log4J can be configured per web-app in an application server, whereas JDK logging is configured per JVM.
The approach I would currently recommend is to use SLF4J as the logging API. You can then pick your logging framework depending on your needs as you discover them.
I did a writeup on what I consider to be best practice in getting started with SLF4J and a simple "log to System.out" which is currently placed at. http://runjva.appspot.com/logging101/index.html
Hopefully it is helpful.
I find Log4j more flexible when it comes to tweaking the logging cfg without re-compiling code in production environment.

Logging using SL4J, Jakarta Commons logging, log4j for third party libraries and my own code

I have some questions about logging, more specifically about setting it up and making sure it works.
The project I'm doing will use Wicket, Spring and Hibernate. I know that Wicket and Hibernate uses Simple Logging Facade for Java (SL4J) and that Spring is using the logging component from Apache Commons.
Will they co-exist happily?
I thought I would use log4j together with both SL4J and the logging component from Apache commons, do you think that's a good idea?
Can I set up them all to output logging data into a common file?
Or should I use separate files?
Or should I store the logging messages in the database? (I'd rather not, as I find grepping etc on text files quite convenient.)
For Spring I guess I need some kind of configuration file for the Apache Commons logging component as well where I direct it to use log4j?
When I've set these up I guess to see that everything works I set the logging level to INFO as it's fairly certain that all three of the frameworks output some information in that mode? Or is there an even better way to make sure?
And my last question. In the project I'm starting, do you recommend that I use SL4J for my own logging purposes? (I thought I would use log4j directly, but that was before I learned a little bit more about logging and a lot of respectable libraries seem to choose the path of a bridge/facade for their logging needs. And if it gets us flexibility without added cost there's no reason not to do it that way.)
I'm looking forward to hearing more from you about how you are doing your logging. It's a new area for me which I'm eager to improve myself in.
Well SLF4J is just a facade, like commons logging, which means they still need something else to work. They permit library authors to not force users into having multiple logging library and configuration. Log4j and logback are regular logging libs.
See here for more info.
SLF4J has a commons logging bridge that you can use to replace the commons logging library. I think the schema there explain the situation very well.
Now, you just need to use slf4j-logj12.jar to have commons logging and slf4j use log4j (or anything else you chose; btw, logback doesn't need an additional library to be used with slf4j) as a backing engine.
You application will thus have
jcl104-over-slf4j.jar (to bridge jakarta commons logging to slf4j)
slf4j.jar (for hibernate and others to use slf4j)
slf4j-logj12.jar (for slf4j to use log4j as a backend)
log4j.jar (for your application to use. all config will also be done here)
Here is how to redirect everything to SLF4J:
remove commons-logging.jar from your classpath. If you are using Maven and have trouble getting rid of commons-logging, see this.
put jcl-over-slf4j.jar in your classpath (it comes in the SLF4J distribution). This is a drop-in replacement that mimics JCL's classes, but calls SLF4J internally. This will take care of Spring, and any other framework that uses JCL.
Connect SLF4J to your favorite backend (Log4J, Logback...) by putting slf4j-xxx.jar in the classpath. Configure the backend to log all categories to one file, and you're done.
As for using SLF4J in your application, it is not strictly necessary. Libraries like JCL and SLF4J were originally designed for people who write libraries and do no want to lock their clients into a particular logging framework.
PS: by the way, JCL = Jakarta Commons Logging

Categories