I'am developing simple Java event library and I want to support more than one logging system.
I have an idea with using own class named LoggerBridge.
public void setLogger(LoggerBridge bridge){
}
public class LoggerBridge{
public void log(Level, String){}
...
}
But this solution is not practical at all, is there some other option how to achieve this result ?
Some bridge, which it supports all types of logging system ?
This is an age old problem and several logging facades were made to allow you to log things in for example libraries, without forcing the user to use the same logging framework you chose (or try to make multiple logging frameworks work nicely together).
One of the earliest ones was commons-logging which is considered outdated these days, but there are a lot of older libraries that use it. It can be bridged to your actual logging system (see below).
Newer ones include SLF4J. These should be used when you're writing a library, so you'd be programming to the SLF4J API instead of an actual logging implementation.
A logging bridge is when you have a library that uses for example log4J, but your other code is using let's say SLF4J with Logback (a quite common combination). The bridge "fakes" being the log4J library, when it actually just redirects the logging to your SLF4J+Logback combination.
Related
When you use slf4j and want to use it with log4j, you just put the log4j jar file in classpath and without any configuration slf4j understand it's impl.
How slf4j do that? what is the mechanism here?
First let me clarify a few points:
SLF4J defines a standard logging API (harder than you'd think if the number of logging APIs are anything to go by).
while there can be many implementations of SLF4J, the common one is Logback.
historically there has been several attempts at logging APIs, these logging APIs have in turn have been used by other APIs you may use in your project - for example Spring usings Commons Logging.
It this last point that's important. Within a project you may use a number of 3rd party APIs each of which use one of the popular logging APIs (Log4J, Commons, JDK, etc). This is a pain because you have to configure each individually.
The solution is to use SLF4J, which provides reimplementations for the legacy logging APIs, which delegate to SLF4J. Hence when whichever 3rd party APIs you use makes a logging call, that call is delegated to SLF4J by the SLF4J implementation of a particular logging API.
And so the mechanism being used is delegation combined with the fact that Java inherently uses the first class it loads from the classpath (in this case the reimplementation of a particular logging API). So as long as the Logging classes in the reimplementation match the definition the calling code was compiled against, the calling code is none the wiser.
I want this library I'm working on to have logging support, but Android and SE have their own ways of logging. In SE you can use System.out.println methods or the java.util.logging.Logger class. Android uses android.util.Log to log on logcat. At first I used reflection to check if android was usable, then reflectively call the log methods in Log.class; but that wasn't a good idea.
My solution is to have the developers using my library handle logs themselves. There will be a Handler interface they set and has an onLog method
public void onLog(int level, String tag, String msg);
The library will call the onLog method on the handlers in my custom Logger class. Is it a good idea to have developers handle the logs instead of the library itself? Seems to be the best solution so far and if I document it good then it should't be an issue.
I agree with you that logging should be delegated to clients, and your homegrown approach is indeed sensible.
IMO, the SLF4J facade would be ideal for your situation. Your library would include the slf4j-api jar and contain SLF4J logging statements. If clients wanted logging, they'd just drop in a logging backend (and an optional config file) into their application's classpath to capture/view your log statements.
The advantages to this approach are that it grants clients the most control with zero coding required to get logging; and that it allows the client to choose among many available backends.
I would use logback as the backend for J2SE apps and logback-android for Android.
You can try microlog
http://code.google.com/p/microlog4android/
It can help you use a consistent logging mechanism across android and java. If you use slf4j, it can be used as a wrapper both for microlog (in case of your android project) and log4j (for your java projects)
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.
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.
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.