我正在开发一个项目,目前正在使用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");
}
}
第二个选项
为每个类使用单独的日志,super和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");
}
}
什么更有意义?为什么?
答案 0 :(得分:82)
我也不愿意。相反,我会在两种情况下都使用正确的类。
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()); }
...
}
如果有一个类调用了很多,你可以覆盖它以给你一个缓存的实例。
答案 1 :(得分:10)
这是我的解决方案(最终静态记录器):
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");
}
}
答案 2 :(得分:4)
两者都有道理。这取决于您的应用程序。
我认为更常用的做法是为每个班级设置私人记录器。这允许您配置每个类和每个包的日志记录。请注意,AbstractFoo
和Foo
可能属于不同的软件包,您可能只希望查看来自Foo
的日志。
此外,如果您想写protected
字段,请务必三思而后行。它并非完全被禁止,而是众所周知的不良做法。它使您的代码可读性降低,难以维护。
答案 3 :(得分:1)
如果在抽象类中创建记录器,则日志将全部标记为源自AbstractFoo。如果您希望/需要查看使用发生日志的子类标记的日志,请为子类创建记录器。
答案 4 :(得分:1)
通过使用构造函数可以实现同样的目的。在 Base 类级别添加记录器,并使用super()从每个 Derived 类设置它。有代码:
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.
}
}
答案 5 :(得分:0)
在抽象类中使用Logger有两个原因(我能想到):
如果您更喜欢静态记录器(这也是我的首选),那么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的解决方案。