简体   繁体   English

使用抽象类进行 Java 日志记录

[英]Java Logging With Abstract Classes

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.我正在做一个项目,目前正在使用 log4j 实现一些日志记录,我很好奇我应该如何实现日志。 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?什么更有意义,为什么?

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.如果有一个类经常调用它,您可以覆盖它以提供一个缓存实例。

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

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.请记住, AbstractFooFoo可能属于不同的包,并且您可能只想查看来自Foo日志。

Moreover always think twice if you want to write protected field.此外,如果您想写入protected字段,请务必三思。 It is not completely forbidden but a well known bad practice.这并不是完全禁止的,而是众所周知的不良做法。 It makes your code less readable and difficult to maintain.它使您的代码可读性降低且难以维护。

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().类级别添加记录器并使用 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.
    }
}

If you create the logger in the abstract class, the logs will all come out tagged as originating from AbstractFoo.如果您在抽象类中创建记录器,则所有日志都将标记为源自 AbstractFoo。 If you want/need to see logs tagged with the child class from which the log occurred, create loggers for the children classes.如果您想/需要查看带有日志发生的子类标记的日志,请为子类创建记录器。

There are 2 reasons (that I can think of) for having a Logger in the abstract class:在抽象类中使用 Logger 有两个原因(我能想到):

  1. Usage of the logger in a method of the abstract class, while still logging out the concrete class as the caller.在抽象类的方法中使用记录器,同时仍将具体类作为调用者注销。
  2. Unified logging or common logging among all concrete classes.所有具体类之间的统一日志记录或公共日志记录。

If you prefer static loggers (that's my preferred choice too), then n1cr4m 's answer solves #1 and #2 very well.如果您更喜欢静态记录器(这也是我的首选),那么n1cr4m的答案很好地解决了 #1 和 #2。

However, if you're more interested in #2 and dislike the fact, that each concrete class needs to implement getLogger() , then you could do the following.但是,如果您对 #2 更感兴趣并且不喜欢每个具体类都需要实现getLogger()的事实,那么您可以执行以下操作。 As an example I'll use a converter:作为示例,我将使用转换器:

public abstract class AbstractConverter{

   protected void logError(Logger logger, String someId, String msg){
       logger.error("Error during conversion of unit \""+ someId + "\": " + msg); 
   }

}

The logger can be a static logger from a concrete class.记录器可以是来自具体类的静态记录器。 Now anytime you log, you will uniformally print the prefix, which also forces the identification of the object it converts.现在,无论何时登录,都会统一打印前缀,这也强制识别它转换的对象。

The drawback of this solution, is that if AbstractConverter needs to use the logger himself in one of its methods, it wont be able to use the logger from the concrete class, unless you also make this a parameter, which I highly discourage.此解决方案的缺点是,如果AbstractConverter需要在其方法之一中自己使用记录器,它将无法使用具体类中的记录器,除非您也将此作为参数,我非常不鼓励这样做。 If you need this kind of functionality, use n1cr4m 's solution.如果您需要这种功能,请使用n1cr4m的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM