Showing posts with label concrete. Show all posts
Showing posts with label concrete. Show all posts

Thursday, April 21, 2011

Log4j: Log concrete and abstract classes

In the past I've often pondered how to get better logging when I'm dealing with abstract classes.

Let's take the following class struture as an example:
  • SomeInterface
    • AbstractImpl
      private static final Logger logger = Logger.getLogger(AbstractImpl.class)
      • ConcreteImpl_A
        private static final Logger logger = Logger.getLogger(ConcreteImpl_A.class)
      • ConcreteImpl_B
        private static final Logger logger = Logger.getLogger(ConcreteImpl_B.class)
This usually results in logs like:
21 Apr 2011 DEBUG [main] (AbstractImpl.java:10) - the actual log message
21 Apr 2011 DEBUG [main] (AbstractImpl.java:10) - the actual log message
... which makes it difficult to distinguish between the concrete implementation classes that are actually being used when the message was logged.

This entry helped me realize that the (AbstractImpl.java:10) portion of the logged line was being placed there by the regex (%F:%L) from the PatternLayout that was specified in the log4j.properties file like so:
log4j.appender.CONSOLE.layout.ConversionPattern=%d{dd MMM yyyy} %5p [%t] (%F:%L) - %m%n
Therefore, the solution would be to add the regex [%c{1}]:
log4j.appender.CONSOLE.layout.ConversionPattern=%d{dd MMM yyyy} %5p [%t] [%c{1}] (%F:%L) - %m%n
Hoping to get logs that look like:
21 Apr 2011 DEBUG [main] [ConcreteImpl_A] (AbstractImpl.java:10) - the actual log message
21 Apr 2011 DEBUG [main] [ConcreteImpl_B] (AbstractImpl.java:10) - the actual log message
... but that will not happen yet because there is still one major flaw in the way the logger code in the java classes above has been written!

The code needs to be like this:
  • SomeInterface
    • AbstractImpl
      protected Logger logger = null;
      • ConcreteImpl_A
        private static final Logger myLogger = Logger.getLogger(ConcreteImpl_A.class)
        public ConcreteImpl_A() {
        super();
        super.logger = myLogger;
        }
      • ConcreteImpl_B
        private static final Logger myLogger = Logger.getLogger(ConcreteImpl_B.class)
        public ConcreteImpl_B() {
        super();
        super.logger = myLogger;
        }