如何记录方法的调用者而不是调用记录器的方法
How to log the caller of a method instead of the method which is calling the Logger
给定日志实用程序 class,如何通过 class 记录所有内容,而不是为每个 class 创建一个 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
class 看起来像这样:
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]; }
}
我已阅读several log4j2 documentation pages, but I found nothing regarding my question, and I also checked several stack overflow questions, but it seems like, whatever I try to search, results in a completely different question。
这甚至可以做到吗?因为我开始怀疑了。请注意,我试图避免使用每个 class 的记录器...否则我不会问这个问题。至少可以创建一个记录自定义堆栈跟踪级别的自定义记录器?
附带说明一下,我的 Maven 依赖项是 the ones given on the log4j2 page:
<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);
它根本不存在。
虽然直接使用 Log4j2 Loggers(使用 %M
参数)是可能的,但这是您试图避免的,IMO,封装日志记录框架是错误的方法。
给定日志实用程序 class,如何通过 class 记录所有内容,而不是为每个 class 创建一个 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
class 看起来像这样:
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]; }
}
我已阅读several log4j2 documentation pages, but I found nothing regarding my question, and I also checked several stack overflow questions, but it seems like, whatever I try to search, results in a completely different question。
这甚至可以做到吗?因为我开始怀疑了。请注意,我试图避免使用每个 class 的记录器...否则我不会问这个问题。至少可以创建一个记录自定义堆栈跟踪级别的自定义记录器?
附带说明一下,我的 Maven 依赖项是 the ones given on the log4j2 page:
<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);
它根本不存在。
虽然直接使用 Log4j2 Loggers(使用 %M
参数)是可能的,但这是您试图避免的,IMO,封装日志记录框架是错误的方法。