Java记录器,可自动确定调用者的类名

时间:2020-03-05 18:58:09  来源:igfitidea点击:
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

解决方案

回答

我们当然可以只将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

回答

我想每节课都会增加很多开销。每个班级都必须"查找"。我们可以创建新的Throwable对象来实现这些目的……这些Throwables并非免费提供。

回答

为什么不?

public static Logger getLogger(Object o) {
  final Logger logger = Logger.getLogger(o.getClass());
  logger.setLevel(ResourceManager.LOGLEVEL);
  return logger;
}

然后,当我们需要一个记录器来上课时:

getLogger(this).debug("Some log message")

回答

我更喜欢为每个类创建一个(静态)记录器(使用它的显式类名)。我比原样使用记录器。

回答

这种机制在运行时付出了很多额外的努力。

如果将Eclipse用作IDE,请考虑使用Log4e。这个方便的插件将使用我们喜欢的日志记录框架为我们生成记录器声明。在编码时要花费很少的精力,但在运行时要少得多的工作。

回答

对于与之一起使用的每个类,无论如何都将不得不查找Logger,因此我们最好在这些类中使用静态Logger。

private static final Logger logger = Logger.getLogger(MyClass.class.getName());

然后,我们仅在需要执行日志消息时引用该记录器。方法与静态Log4J Logger已经执行的操作相同,所以为什么要重新发明轮子呢?

回答

除非我们真的需要Logger是静态的,否则可以使用

final Logger logger = LoggerFactory.getLogger(getClass());

回答

创建堆栈跟踪是一个相对较慢的操作。呼叫者已经知道它所在的类和方法,因此浪费了精力。解决方案的这方面效率很低。

即使我们使用静态类信息,也不应为每个消息再次获取Logger。来自Log4j的作者Ceki Glc:

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的常规高效方法:

private static final Logger log = Logger.getLogger(MyClass.class);

请注意,这为我们为层次结构中的每种类型提供了单独的Logger。如果我们想出一种在实例上调用getClass()的方法,则将在子类型的记录器下看到基本类型记录的消息。在某些情况下这也许是合乎需要的,但我发现它令人困惑(而且无论如何,我倾向于更倾向于使用组合而不是继承)。

显然,通过getClass()使用动态类型将要求我们至少每个实例获取记录器一次,而不是像使用静态类型信息的建议用法那样每个类一次获取记录器。

回答

我们无需创建新的Throwable对象。你可以打电话
Thread.currentThread()。getStackTrace()[1]

回答

假设我们要保留对记录器的静态引用,这是一个独立的静态单例:

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

用法很干净:

Logger logger = LoggerUtils.getLogger();

回答

实际上,LogUtils类中有一些非常相似的东西。是的,这有点棘手,但就我而言,优势是值得的。我们想确保不会因为重复调用而产生任何开销,因此我们的(有点hackyly)确保只能从静态初始化程序上下文中调用它:

private static final Logger LOG = LogUtils.loggerForThisClass();

如果是通过普通方法或者实例初始化程序(即如果在上面未使用"静态"的方法)调用它,则会失败,以降低性能开销的风险。方法是:

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

任何人问这有什么好处

= Logger.getLogger(MyClass.class);

也许从来没有必要与从其他地方复制并粘贴该行而忘记更改类名的人打交道,而让我们处理将所有内容发送到另一个记录器的类。

回答

那么最好的事情就是两者的混合。

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

然后在每个班级:

private static final Logger LOG = LoggerUtil.getLogger();

在代码中:

LOG.fine("debug that !...");

我们将获得静态记录器,我们只需在每个类中进行复制和粘贴即可,而不会产生开销。

阿拉