1 2 3 4 5 6 7
| public static Logger getLogger() {
final Throwable t = new Throwable();
final StackTraceElement methodCaller = t.getStackTrace()[1];
final Logger logger = Logger.getLogger(methodCaller.getClassName());
logger.setLevel(ResourceManager.LOGLEVEL);
return logger;
} |
此方法将返回一个知道其正在记录的类的记录器。
有反对的想法吗?
很多年后:https://github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.java
n
创建堆栈跟踪是一个相对较慢的操作。您的呼叫者已经知道它所在的类和方法,因此浪费了精力。解决方案的这方面效率很低。
即使您使用静态类信息,也不应为每个消息再次获取Logger。来自Log4j的作者,Ceki G ?? lc ??:
The most common error in wrapper classes is the invocation of the Logger.getLogger method on each log request. This is guaranteed to wreak havoc on your application's performance. Really!!!
这是在类初始化期间获取Logger的常规,有效的习惯用法:
1
| private static final Logger log = Logger.getLogger(MyClass.class); |
请注意,这为层次结构中的每种类型提供了单独的Logger。如果您想出一种在实例上调用getClass()的方法,则将在子类型的记录器下看到由基本类型记录的消息。在某些情况下这也许是合乎需要的,但我发现它令人困惑(而且无论如何,我倾向于更偏重于继承)。
很显然,通过getClass()使用动态类型将要求您至少每个实例一次获取记录器,而不是像使用静态类型信息的建议用法那样每个类一次获取记录器。
我们实际上在LogUtils类中有一些非常相似的东西。是的,这有点棘手,但是就我而言,优势是值得的。我们想确保不会因为被重复调用而产生任何开销,因此我们(有点hackyly)确保只能从静态初始化器上下文la:
中调用它
1
| private static final Logger LOG = LogUtils.loggerForThisClass(); |
如果是通过常规方法或实例初始化程序(即,如果在上面未使用"静态"的方法)调用,则会失败,以降低性能开销的风险。方法是:
1 2 3 4 5 6
| public static Logger loggerForThisClass() {
// We use the third stack element; second is this method, first is .getStackTrace()
StackTraceElement myCaller = Thread.currentThread().getStackTrace()[2];
Assert.equal("<clinit>", myCaller.getMethodName());
return Logger.getLogger(myCaller.getClassName());
} |
任何人问这比
有什么优势
1
| = Logger.getLogger(MyClass.class); |
也许从来没有必要与从其他地方复制并粘贴该行而忘记更改类名的人打交道,而让您处理将其所有内容发送到另一个记录器的类。
我想每门课都会增加很多开销。每个班级都必须"查找"。您可以创建新的Throwable对象来实现这些目的……这些Throwables并非免费提供。
假设您要保留对记录器的静态引用,这是一个独立的静态单例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class LoggerUtils extends SecurityManager
{
public static Logger getLogger()
{
String className = new LoggerUtils().getClassName();
Logger logger = Logger.getLogger(className);
return logger;
}
private String getClassName()
{
return getClassContext()[2].getName();
}
} |
用法很干净:
1
| Logger logger = LoggerUtils.getLogger(); |
对于与之一起使用的每个类,无论如何都将不得不查找Logger,因此您最好在这些类中使用静态Logger。
1
| private static final Logger logger = Logger.getLogger(MyClass.class.getName()); |
然后,您仅在需要执行日志消息时引用该记录器。您的方法执行的操作与静态Log4J Logger已经执行的操作相同,所以为什么要重新发明轮子呢?
n
那么最好的事情就是两者的混合。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class LoggerUtil {
public static Level level=Level.ALL;
public static java.util.logging.Logger getLogger() {
final Throwable t = new Throwable();
final StackTraceElement methodCaller = t.getStackTrace()[1];
final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(methodCaller.getClassName());
logger.setLevel(level);
return logger;
}
} |
然后在每个班级:
1
| private static final Logger LOG = LoggerUtil.getLogger(); |
在代码中:
1
| LOG.fine("debug that !..."); |
您将获得可以复制的静态记录器
您不需要创建新的Throwable对象。你可以打电话
Thread.currentThread().getStackTrace()[1]
我更喜欢为每个类创建一个(静态)记录器(使用它的显式类名)。我比原样使用记录器。
您当然可以只使用具有适当模式布局的Log4J:
For example, for the class name"org.apache.xyz.SomeClass", the pattern %C{1} will output"SomeClass".
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
n
n
n
n
n
此机制在运行时付出了很多额外的努力。
如果将Eclipse用作IDE,请考虑使用Log4e。这个方便的插件将使用您喜欢的日志记录框架为您生成记录器声明。在编码时的工作量要少一些,但在运行时的工作量要少得多。
n
为什么不呢?
1 2 3 4 5
| public static Logger getLogger(Object o) {
final Logger logger = Logger.getLogger(o.getClass());
logger.setLevel(ResourceManager.LOGLEVEL);
return logger;
} |
然后在需要记录器上课时:
1
| getLogger(this).debug("Some log message") |
n
除非您真的需要Logger保持静态,否则可以使用
1
| final Logger logger = LoggerFactory.getLogger(getClass()); |