Registro de Java con clases abstractas

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:

Primera opción

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");
    }
}

Segunda opción

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?

preguntado el 28 de agosto de 12 a las 14:08

5 Respuestas

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.

Respondido el 21 de enero de 15 a las 08:01

So far I've seen two approaches: static loggers (as in the question) and non-static loggers (as in your example). Aren't static loggers better solution (one instance of logger per all instances)? - Om nom nom

static loggers are better if they are the same for all instances. In the abstract class case, the class of the instances are not all the same. - pedro laurey

I like this, it seems like a good way to combine both options. You end up with a single log but it binds to the proper class. +1 - shuniar

@Emilio I would call log() a getter as all it does it is get a value. What would you use instead of protected? - pedro laurey

@Emilio The problem with using log as a field is you have to add code to every sub-class to use the appropriate logger. Although, using a field is much more efficient per call esp if you are not actually logging i.e. logging is off. - pedro laurey

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");
    }
}

Respondido 27 Oct 18, 00:10

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 y Foo may belong to different packages and probably you want to see logs from Foo solamente.

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.

Respondido 28 ago 12, 14:08

The same can be achieved by playing with constructors. Add logger at the El pareo de bases class level and set it from every Derivado 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.
    }
}

Respondido el 28 de junio de 17 a las 06:06

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.

Respondido 28 ago 12, 14:08

"If you create the logger in the abstract class, the logs will all come out tagged as originating from AbstractFoo" -> Nope, not true if you use the Accepted Answer by @Peter_Lawrey. Then you get logs tagged with class doing the logging, always. - cellepo

The 'problem' with Lawrey's answer is that they are now instance based loggers, which isn't idea. - yograndegordo

@MeBigFatGuy Is it bad to have instance based loggers? - Valijon

Well you are wasting memory and time allocating these things, and creating more garbage for no reason. There are certainly much more heinous problems in life besides this, but it's kind of dumb. - yograndegordo

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.