How to decouple logging implementation and API? - java

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.

Related

Logging-Strategy (slf4j?) for external libraries

I want to provide a client-library for wrapping rest-request to a server and log errors, so that a client can use it in his app and also see the logs. (There is also a question if i should just log the errors or rethrow it. When i use an asynchronized call (multithreaded) this might be quite tricky..)
I read that slf4j might help, because the client, who is using the library, can choose which logging framework he prefers.
Somethings puzzles me about this slf4j-thing. If he gets my library and i just provide, let's say the slf4j-api, errors will be thrown, cause the SLF4J bindings aren't included. The solution might be that he has to include the binding on his own, and the question is if he is willing to read the README for this crucial information.
If i include one "standard"-slf4j binding (e.g. the simple one), the app can't "override" this, because there is just one binding allowed on the classpath. It won't be flexible anymoe
So i am thinking to just use log4j and forget every other logging-framework. I may think to complicated on this subject, maybe someone might help me out on this?
You have to remember, your library does not set the wrapping application's classpath. The wrapping application will set a classpath that includes your library, the slf4j API library and the implementing library.
The wrapping application will take care of what slf4j implementation to use and setup all of the logging parameters. You just need to worry about logging your libraries events with the slf4j API. This is common practice, don't worry about the wrapping application.
By packaging log4j within your library, you are defeating the purpose of a logging facade. Doing so will not allow the user to pick the slf4j implementation.

How to change slf4j level at runtime?

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.

Java logging interface

If I've to distribute a certain framework like a customized validation framework which can be used in many projects, how do I handle logging within this framework so that it uses the same logging method as the project in which it is being used? i.e I've written a logger interface with the usual debug,warn,info... methods and the implementation of this interface can implement those methods using log4j or any other logging methods. If I distribute this as a jar, how can different projects use this jar with their logging framework?
I would strongly suggest that instead of writing yet another logging framework you recode your application to use the SLF4J logging API instead. All the work of interfacing to other logging implementations have been done, and is well known in the industry.
An added benefit is that you get {}-placeholders, which allow you to just do
log.debug("a={}, b={}", a, b);
and the a.toString() and b.toString() are only called when the string will actually be logged. This allows for a lot of log statements which will not actually be executed unless you need them to run in a debug setting.
There are some libraries that provide an abstraction layer over log4j, java.util.logging etc. They act as the 'interface' and then the person using your project can use the implementation of their choosing. Have a look at Apache Commons Logging and SLF4J.

Apache Commons Logging implementation differences

I will try to use the Apache Commons Logging to logs in my system. I need some simple, just to keep up on the information and errors, nothing too complex.
I saw that there a lot of implementations there (SimpleLog, AvalonLog, etc.) Someone can explain me the most appropriate or the most complete/full of resources?
Actually I don't know which one to use.
Commons-logging is not a simple logging mechanism. It's a method of allow you to write a library that works regardless of the logging mechanism chosen by someone who incorporates your library.
If you want a simple logging mechanism, just use java.util.logging directly. If you want an even simpler API, use slf4j and then use their 'simple' backend.
You don't need commons-logging unless you have to fit into other people's environments.

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.

Categories