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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/80692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:02:49  来源:igfitidea点击:

Java logger that automatically determines caller's class name

javaloggingstack-trace

提问by yanchenko

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

This method would return a logger that knows the class it's logging for. Any ideas against it?

此方法将返回一个记录器,该记录器知道它正在记录的类。有什么反对的想法吗?

Many years later: https://github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.java

许多年后:https: //github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.java

采纳答案by Daan

I guess it adds a lot of overhead for every class. Every class has to be 'looked up'. You create new Throwable objects to do that... These throwables don't come for free.

我想它为每个类增加了很多开销。每个班级都必须“查找”。你创建新的 Throwable 对象来做到这一点......这些 throwable 不是免费的。

回答by Ian

You could of course just use Log4J with the appropriate pattern layout:

您当然可以只使用具有适当模式布局的 Log4J:

For example, for the class name "org.apache.xyz.SomeClass", the pattern %C{1} will output "SomeClass".

例如,对于类名“org.apache.xyz.SomeClass”,模式 %C{1} 将输出“SomeClass”。

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

回答by Mario Ortegón

Why not?

为什么不?

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

And then when you need a logger for a class:

然后当你需要一个类的记录器时:

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

回答by Philip Helger

I prefer creating a (static) Logger for each class (with it's explicit class name). I than use the logger as is.

我更喜欢为每个类创建一个(静态)记录器(带有明确的类名)。我比原样使用记录器。

回答by Bill Michell

This mechanism puts in a lot of extra effort at runtime.

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

If you use Eclipse as your IDE, consider using Log4e. This handy plugin will generate logger declarations for you using your favourite logging framework. A fraction more effort at coding time, but muchless work at runtime.

如果您使用 Eclipse 作为 IDE,请考虑使用Log4e。这个方便的插件将使用您最喜欢的日志记录框架为您生成记录器声明。在编码时需要付出更多的努力,但在运行时的工作却少得多

回答by 18Rabbit

For every class that you use this with, you're going to have to look up the Logger anyway, so you might as well just use a static Logger in those classes.

对于您使用它的每个类,无论如何您都必须查找 Logger,因此您最好在这些类中使用静态 Logger。

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

Then you just reference that logger when you need to do your log messages. Your method does the same thing that the static Log4J Logger does already so why reinvent the wheel?

然后,您只需在需要处理日志消息时引用该记录器。您的方法与静态 Log4J Logger 已经做了同样的事情,那么为什么要重新发明轮子呢?

回答by Asgeir S. Nilsen

Unless you reallyneed your Logger to be static, you could use

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

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

回答by erickson

Creating a stack trace is a relatively slow operation. Your caller already knows what class and method it is in, so the effort is wasted. This aspect of your solution is inefficient.

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

Even if you use static class information, you should not fetch the Logger again for each message. From the authorof Log4j,Ceki Gülcü:

即使您使用静态类信息,也不应该为每条消息再次获取 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.getLogger 方法。这肯定会对您的应用程序的性能造成严重破坏。真的!!!

This is the conventional, efficient idiom for getting a Logger is during class initialization:

这是在类初始化期间获取 Logger 的传统、有效的习惯用法:

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

Note that this gives you a separate Logger for each type in a hierarchy. If you come up with a method that invokes getClass()on an instance, you will see messages logged by a base type showing up under the subtype's logger. Maybe this is desirable in some cases, but I find it confusing (and I tend to favor composition over inheritance anyway).

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

Obviously, using the dynamic type via getClass()will require you to obtain the logger at least once per instance, rather than once per class like the recommended idiom using static type information.

显然,使用动态类型 viagetClass()将要求您至少为每个实例获取一次记录器,而不是像使用静态类型信息的推荐习语那样每个类获取一次。

回答by ykaganovich

You don't need to create a new Throwable object. You can just call Thread.currentThread().getStackTrace()[1]

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

回答by EGB

Assuming you are keeping static refs to the loggers, here's a standalone static singleton:

假设您保持对记录器的静态引用,这是一个独立的静态单例:

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

Usage is nice and clean:

用法很好很干净:

Logger logger = LoggerUtils.getLogger();