Using Log4j efficiently
Hi,
I've been using Log4j, and I found it a little troublesome to declare an instance variable everywhere and pass the class name to it; like this:
publicclass UsesLogger{
Logger logger = Logger.getLogger(this.class);
...
publicvoid log(){
logger.debug("bla bla");
}
}
So I thought I could create a wrapper class to encapsulate the logger. For instance:
publicclass MyLogger{
publicstaticvoid log(Class clazz, String message){
Logger logger = Logger.getLogger(clazz);
logger.debug(message);
}
}
But I also didn't like passing the class object every time I want to log a message. So the following came to my mind:
publicclass MyLogger{
privatestatic Exception ex =new Exception();
publicstaticvoid log(String message){
ex.fillInStackTrace();
StackTraceElement[] ste = ex.getStackTrace();
Logger logger = Logger.getLogger(ste[1].getClassName());
//I even can add the method name to the message using ste[1].getMethodName()
logger.debug(message);
}
}
So the other classes do the following:
publicclass UsesLogger(){
publicvoid aMethod(){
MyLogger.log("inside aMethod");
}
}
My question is, is this approach efficient? especially that the ex.fillInStackTrace() method is synchronized, so it might be a bit costly.
Any ideas?
P.S: I'm not sure if this is the right thread to post in.
[2708 byte] By [
nawad980a] at [2007-11-26 17:19:43]

# 1
> I've been using Log4j, and I found it a little
> troublesome to declare an instance variable
> everywhere and pass the class name to it; like this:
"troublesome"? Why?
The normal pattern is to make it static so there isn't one logger per class instance:
private static final Logger logger = Logger.getLogger(MyClass.class);
> My question is, is this approach efficient? especially
> that the ex.fillInStackTrace() method is
> synchronized, so it might be a bit costly.
I can't speak about efficiency, but your proposed implementation is not thread safe.
If two threads call your log() method at once, there is potential for each of them to trash the stack trace in the shared exception object.
Object creation is very very cheap in Java. Since you're going to have to pay the price for creating the stack trace any way, I would consider just creating a new exception within your log method, rather than re-using one and updating its stack trace.
# 2
> I found it a little troublesome to declare an instance variable everywhere and pass the class name to it;
What is troublesome to you about this?
> The normal pattern is to make it static so there isn't one logger per class instance:
There won't be one logger per instance, even if you don't make it static. If the named logger exists, log4j won't create a new one. It will simply return a reference to the existing one.
~
# 3
> There won't be one logger per instance, even if you
> don't make it static. If the named logger exists,
> log4j won't create a new one. It will simply return a
> reference to the existing one.
My bad. Having never even considered doing it the other way, I never looked into what log4j's factory methods do! :-)
# 4
> What is troublesome to you about this?
I'm not really sure, but I didn't like the idea of repeating any piece of code anywhere. In this case: including the Logger class and defining its variable in every class that needs to log anything. That's why I thought of an alternative to centralize the access to the logger using my own utility class.
So my question remains: is this approach efficient?
Regards,
# 5
> > What is troublesome to you about this?
>
> I'm not really sure, but I didn't like the idea of
> repeating any piece of code anywhere.
That's a bit dogmatic, in my opinion. I think DRY is a good principle to follow, but declaring a Logger for a particular class isn't what I'd consider repeating code. If a class needs an instance of a Logger, I think it's perfectly appropriate to declare one (or have one injected -- that's for duffymo and the rest of the Spring zealots ;o)...
> In this case: including the Logger class and defining its variable
> in every class that needs to log anything. That's why
> I thought of an alternative to centralize the access
> to the logger using my own utility class.
>
> So my question remains: is this approach efficient?
I know these types of answers are unsatisfying, but it really depends on what criteria you're using to measure efficiency. In this case, I'd say not really. Your utility class is just adding another layer to the logging functionality. If you think you'll be changing logging frameworks often, it might be beneficial from a design standpoint to abstract out the logging, but I'd be surprised if you'd actually change the underlying logging implementation enough to warrant the new layer. I believe the impact is negligible to nonexistent from an application performance standpoint, but you could always measure it if you wanted.
But there are other options [url=http://www.google.com/search?q=AOP+logging]such as AOP[/url], that may be able to provide you with "cross-cutting" logging functionality you're looking for without sullying your class definitions with logging code.
Cheers!
~
# 6
Well, I guess I'm overreacting, it seems that the old usual way is ok with everybody :)
Anyway, I'm going to create the wrapper class and declare the static methods that I need to be accessed directly from my code, it still seems better to me rather than creating the Logger field in every calss. Here's my final decision:
import org.apache.log4j.Logger;
public class Log {
public static void debug(Object caller, String message) {
Logger logger = Logger.getLogger(caller.getClass());
logger.debug(message);
}
}
This is the best answer that I could get. Here's your Duke Stars :)
# 7
> Hi,
> I've been using Log4j, and I found it a little
> troublesome to declare an instance variable
> everywhere and pass the class name to it; like this:
>
Myself I just hacked the log4j code so I could produce my own logger and use it like the following...
public class UsesLogger
{
public void log()
{
MyLog.debug("bla bla");
}
}