Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it efficient to obtain a Logger from a static final variable initializer?

Tags:

java

log4j

We have a lot of class code which has some boilerplate like the following:

private static Logger logger = null;

private static Logger getLogger() {
  if (logger == null) {
    logger = Logger.getLogger(MyClass.class);
  }
  return logger;
}

The idea is that the class can log debug stuff into the Logger. The first code which needs to log something invokes getLogger() and that brings the logger into existence.

There are a couple of things I don't like about this pattern. First the singleton getLogger() is not synchronized and synchronizing it, while correct would put a burden on each subsequent call for no reason.

I really want to be able to condense it down to just this:

private static final Logger logger = Logger.getLogger(MyClass.class);

Then I can just reference logger directly and not even bother with a singleton getter.

The problem I fear is that by doing this I cause a Logger to be created when the class is loaded even if the logger is never called. I have 10,000+ odd classes all calling getLogger(), so how many instances of Logger am I actually creating here? If my log4j properties contains a few appenders am I just referencing the same logger over and over, or I am I creating 10,000 of these things?

like image 458
locka Avatar asked Sep 06 '11 11:09

locka


1 Answers

If you use the default Log4j configuration (i.e. default LoggerRepository, DefaultCategoryFactory etc.) then you will create 10'000 Logger instances. How much memory do they consume? No one except God and your Profiler knows this. (And my guess only the latter one would tell that to you).

If the memory footprint would be too much for your environment, move Logger initialization to the static inner class like this:

static class LoggerHolder {
  static Logger logger = Logger.getLogger(MyClass.class);
}

private static Logger getLogger() {
  return LoggerHolder.logger;
}

That way the instance of Logger will be only created on the first getLogger call. (This technique is known as the Initialization On Demand Holder (IODH), it is thread-safe and has zero synchronization overhead).

And may I give you one offtopic suggestion? Consider to replace Log4J with the combination of SLF4J+Logback libraries. They are written by the very same authors and described as "a successor to the popular log4j project, picking up where log4j leaves off". You can read more in this SO thread.

like image 96
Idolon Avatar answered Sep 28 '22 22:09

Idolon