72

我正在做一个项目,目前正在使用 log4j 实现一些日志记录,我很好奇我应该如何实现日志。我正在讨论的两个实现如下:

第一个选项

对该类和所有子类使用超类中的单个日志:

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

第二种选择

为每个类、超级类和子类使用单独的日志:

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

什么更有意义,为什么?

4

6 回答 6

114

我也不会。相反,我会让它在两种情况下都使用正确的类。

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

    ...
}

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

如果您没有进行大量日志记录(无论如何这是一个好主意),您可以使用一种方法。

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

    ...
}

如果有一个类经常调用它,你可以覆盖它来给你一个缓存的实例。

于 2012-08-28T13:44:49.947 回答
14

这是我的解决方案(最终静态记录器):

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");
    }
}
于 2015-04-08T08:20:25.990 回答
5

两者都有道理。这取决于您的应用程序。

我认为更常用的做法是为每个班级设置私人记录器。这允许您为每个类和每个包配置日志记录。请记住,它AbstractFoo可能Foo属于不同的包,并且您可能只想查看来自的日志Foo

此外,如果您想写protected字段,请务必三思而后行。这不是完全禁止的,而是众所周知的不良做法。它使您的代码可读性降低并且难以维护。

于 2012-08-28T13:48:58.413 回答
4

同样可以通过使用构造函数来实现。在基类级别添加记录器,并使用 super()从每个派生类中设置它。有代码:

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.
    }
}
于 2017-06-28T05:05:31.977 回答
0

如果您在抽象类中创建记录器,则所有日志都将标记为源自 AbstractFoo。如果您希望/需要查看带有发生日志的子类标记的日志,请为子类创建记录器。

于 2012-08-28T13:51:01.453 回答
0

在抽象类中有一个 Logger 有两个原因(我能想到):

  1. 在抽象类的方法中使用记录器,同时仍将具体类作为调用者注销。
  2. 所有具体类之间的统一日志记录或通用日志记录。

如果您更喜欢静态记录器(这也是我的首选),那么n1cr4m的答案很好地解决了 #1 和 #2。

但是,如果您对 #2 更感兴趣并且不喜欢每个具体类都需要实现的事实,getLogger()那么您可以执行以下操作。例如,我将使用转换器:

public abstract class AbstractConverter{

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

}

记录器可以是来自具体类的静态记录器。现在,无论何时登录,您都将统一打印前缀,这也强制识别它转换的对象。

此解决方案的缺点是,如果AbstractConverter需要在其方法之一中使用记录器自己,它将无法使用具体类中的记录器,除非您也将其设为参数,我非常不鼓励这样做。如果您需要这种功能,请使用n1cr4m的解决方案。

于 2020-03-20T19:56:57.490 回答