Should logger be private static or not
The advantage of the non-static form is that you can declare it in an (abstract) base class like follows without worrying that the right classname will be used:
protected Log log = new Log4JLogger(getClass());
However its disadvantage is obviously that a whole new logger instance will be created for every instance of the class. This may not per se be expensive, but it adds a significant overhead. If you'd like to avoid this, you'd like to use the static
form instead. But its disadvantage is in turn that you have to declare it in every individual class and take care in every class that the right classname is been used during logger's construction because getClass()
cannot be used in static context. However, in the average IDE you can create an autocomplete template for this. E.g. logger
+ ctrl+space
.
On the other hand, if you obtain the logger by a factory which in turn may cache the already-instantiated loggers, then using the non-static form won't add that much overhead. Log4j for example has a LogManager
for this purpose.
protected Log log = LogManager.getLogger(getClass());
The most important difference is how it affects your log files: in which category do logs go?
- In your first choice, the logs of a subclass end up in the category of the superclass. That seem very counter-intuitive to me.
There is a variant of your first case:
protected Log log = new Log4JLogger(getClass());
In that case, your log category says which object the code that logged was working on.
In your second choice (private static), the log category is the class that contains the logging code. So normally the class that is doing the thing that is being logged.
I would strongly recommend that last option. It has these advantages, compared to the other solutions:
- There is a direct relation between the log and the code. It is easy to find back where a log message came from.
- If someone has to tune logging levels (which is done per category), it is usually because they are interested (or not) in some particular messages, written by a particular class. If the category is not the class that is writing the messages, it is harder to tune the levels.
- You can log in static methods
- Loggers only need to be initialized (or looked up) once per class, so at startup, instead of for every instance created.
It also has disadvantages:
- It needs to be declared in every class where you log messages (no reuse of superclass loggers).
- You need to take care to put the right classname when initializing the logger. (But good IDE's take care of that for you).
Use inversion of control and pass the logger into the constructor. If you create the logger inside the class you are going to have a devil of a time with your unit tests. You are writing unit tests aren't you?
I used to think that all loggers should be static; however, this article at wiki.apache.org brings up some important memory concerns, regarding classloader leaks. Declaring a logger as static prevents the declaring class (and associated classloaders) from being garbage collected in J2EE containers that use a shared classloader. This will result in PermGen errors if you redeploy your application enough times.
I don't really see any way to work around this classloader leak issue, other than declaring loggers as non-static.