如何记录方法的调用者,而不是正在调用Logger的方法



给定一个日志工具类,如何通过该类记录所有内容,而不是为每个类创建一个Logger对象?

例如,不用:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Main {
private static final Logger LOG = LogManager.getLogger(Main.class);
public static void main(String[] args) {
LOG.info("Application started!");
}
}

我想这样做:

import my.utils.LogUtils;
public class Main {
public static void main(String[] args) {
LogUtils.info("Application started!");
}
}

我的LogUtils课是这样的:

package my.utils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.HashMap;
import java.util.Map;
public final class LogUtils {
private LogUtils() {
throw new AssertionError("private constructor: " + LogUtils.class.getName());
}
private static final Map<Class<?>, Logger> LOGGERS = new HashMap<>();
static {
Class<?> current = LogUtils.class;
LOGGERS.put(current, LogManager.getLogger(current));
}
public static void info(Object msg) {
Logger logger = getFor(getCallerClass());
// logger.info()... Here's where I am stuck! What I want to log in the stack trace is the *caller* of the "info" method, not the "info" method.
}
private static Logger getFor(Class<?> clazz) { return LOGGERS.computeIfAbsent(clazz, key -> LogManager.getLogger(key)); }
private static Class<?> getCallerClass() {
try {
return Class.forName(getCaller(3).getClassName());
} catch (ClassNotFoundException e) {
return LogUtils.class;
}
}
// This method should return "main" method name, but it's not being used because I don't know what should I do now
private static String getCallerMethod() { return getCaller(3).getMethodName(); }
private static StackTraceElement getCaller(int level) { return Thread.currentThread().getStackTrace()[level]; }
}

我已经阅读了几个log4j2文档页面,但我没有发现关于我的问题,我也检查了几个堆栈溢出问题,但似乎,无论我试图搜索什么,结果都是一个完全不同的问题。

这是可能的吗?因为我开始怀疑了。表示我试图避免每个类使用一个Logger…否则我不会问这个问题。它是,至少,可以创建一个自定义日志记录器记录自定义堆栈跟踪级别?

附带说明一下,我的Maven依赖项是log4j2页面上给出的依赖项:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>

我还必须提到,在回答时,有这个调用:

LOG.log(LoggingHelper.class.getCanonicalName(), Level.INFO, message, null);

我找不到org.apache.logging.log4j.Logger的方法(Javadoc喜欢)是这样指的:

Logger#log(String, Level, Object, Throwable);

It根本不存在

当直接使用Log4j2 Loggers(使用%M参数)时,这是可能的,这是您试图避免的,在我看来,封装日志框架是错误的方法。

  • 如果您希望将日志记录实现与代码分离,请使用slf4j
  • 如果您关心性能,请直接使用log4j2(尽管使用%M记录调用方方法的开销非常大,如这里所述
  • 如果您关心由于重新创建日志实例而导致的日志GC开销(对于新的ZGC/Shenandoah GC,您不应该这样做),那么log4j2在幕后负责(如此处所述),所以不用担心
  • 还可以考虑使用Lombok进行Log4j2日志程序实例化。请注意,Lombok/Scala/Kotlin Log4j2扩展非常支持直接实例化记录器,这可能是正确的方法。

最新更新