Java Logging With Abstract Classes

JavaInheritanceLoggingAbstract Class

Java Problem Overview


I am working on a project, and am currently working on implementing some logging with log4j and I was curious about how I should go about implementing the logs. The two implementations I am kicking around are as follows:

First Option

Use single log from super class for that class and all sub classes:

public abstract class AbstractFoo {
    protected static Log LOG = LogFactory.getLog(AbstractFoo.class);

    ...
}

public class Foo extends AbstractFoo {
    public void someMethod() {
        LOG.info("Using abstract log");
    }
}

Second Option

Use individual logs for each class, super and subs:

public abstract class AbstractFoo {
    private static Log LOG = LogFactory.getLog(AbstractFoo.class);

    ...
}

public class Foo extends AbstractFoo {
    private static Log LOG = LogFactory.getLog(Foo.class);        

    public void someMethod() {
        LOG.info("Using own log");
    }
}

What makes more sense and why?

Java Solutions


Solution 1 - Java

I wouldn't do either. Instead I would make it use the correct class in both cases.

public abstract class AbstractFoo {
    protected final Log log = LogFactory.getLog(getClass());

    ...
}

public class Foo extends AbstractFoo {
    public void someMethod() {
        log.info("Using abstract log");
    }
}

If you are not doing lots of logging (which is a good idea anyway) you can use a method instead.

public abstract class AbstractFoo {
    protected Log log() { return LogFactory.getLog(getClass()); }

    ...
}

If there is a class which calls this a lot you can override it to give you a cached instance.

Solution 2 - Java

This is my solution (final static logger):

public abstract class AbstractFoo {
     protected abstract Log getLogger();
     public doSomething() {
          getLogger().info("log something");
     }
}

public class Foo extends AbstractFoo {
    private static final Log log = Log.getLogger(Foo.class);
    
    protected Log getLogger() {
         return log;
    }
    public doSomethingElse() {
          log.info("log somethingElse");
    }
}

Solution 3 - Java

Both make sense. It depends on your application.

I think that more often used practice is to have private logger for each class. This allows you to configure logging both per class and per package. Remember, that AbstractFoo and Foo may belong to different packages and probably you want to see logs from Foo only.

Moreover always think twice if you want to write protected field. It is not completely forbidden but a well known bad practice. It makes your code less readable and difficult to maintain.

Solution 4 - Java

The same can be achieved by playing with constructors. Add logger at the Base class level and set it from every Derived class using super(). There is the code :

public abstract class AbstractFoo {
    
    protected Log log;  // base abstract class has a Log object.
    
    public AbstractFoo(Log logger) {   // parameterized constructor for logger, to be used by the derived class.
        this.log = logger;
    }
    
    public doSomething() {        // common method for all the derived classes.
      log.info("log something");
    }
    // rest of business logic.
}

public class Foo extends AbstractFoo {
    
    public Foo(){
        super(LogFactory.getLog(AbstractFoo.class));
    }
    
    public void someMethod() {
        log.info("Using own log");     // this uses its own logger.
    }
}

Solution 5 - Java

If you create the logger in the abstract class, the logs will all come out tagged as originating from AbstractFoo. If you want/need to see logs tagged with the child class from which the log occurred, create loggers for the children classes.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionshuniarView Question on Stackoverflow
Solution 1 - JavaPeter LawreyView Answer on Stackoverflow
Solution 2 - Javan1cr4mView Answer on Stackoverflow
Solution 3 - JavaAlexRView Answer on Stackoverflow
Solution 4 - JavaShubham MishraView Answer on Stackoverflow
Solution 5 - JavaherrtimView Answer on Stackoverflow