我的应用程序有一个自制日志记录类,我正在迁移到使用log4j。但是,由于我使用自制程序类将应用程序的其余日志语句传递给log4j,因此输出语句将记录为来自包装类而不是源类。
除了为每个日志语句创建新的org.apache.log4j.Logger实例之外,还有办法确保显示“正确”的源吗?我也尝试过使用Logger.log(String callerFQCN,Priority level,Object message,Throwable t)方法,但它似乎不起作用,例如:
public class Logger2 {
public static org.apache.log4j.Logger log4JLogger = org.apache.log4j.Logger.getLogger(Logger2.class);
public static void warning(Object source, String message) {
log(source, message, Level.WARN, null)
}
private static void log(Object source, String message, Level level, Throwable t) {
String className = source.getClass().getName();
System.out.println("Logging class should be " + className);
log4JLogger.log(className, loggingLevel, message, t);
}
}
被召唤时:
public void testWarning() {
Logger2.warning(new Integer(3), "This should warn");
}
打印:
Logging class should be java.lang.Integer
2010-05-25 10:49:57,152 WARN test.Logger2 - This should warn
答案 0 :(得分:4)
我的自制日志记录解决方案使用log4j的LocationInfo类来查找源代码信息。
使用此解决方案,locationInfo
对象包含来自使用loggerName
调用记录器的对象的信息。
以下是使用log4j记录的记录器的简化版本:
public void log(Level level, String message) {
LocationInfo locationInfo = new LocationInfo(new Throwable(),
loggerName);
MDC.put(LINE_NUMBER, locationInfo.getLineNumber());
MDC.put(FILE_NAME, locationInfo.getFileName());
MDC.put(CLASS_NAME, locationInfo.getClassName());
MDC.put(METHOD_NAME, locationInfo.getMethodName());
MDC.put(FQMETHOD_NAME, locationInfo.getClassName() + "."
+ locationInfo.getMethodName());
logger.log(level, message);
MDC.remove(LINE_NUMBER);
MDC.remove(FILE_NAME);
MDC.remove(CLASS_NAME);
MDC.remove(METHOD_NAME);
MDC.remove(FQMETHOD_NAME);
}
顺便说一句:Level,MDC和Logger类都是log4j类。
对评论的回复:
MDC对象存储在ThreadLocal
对象上,可供log4j记录器访问。
来自MDC Java文档:
MDC是基于每个线程管理的。
答案 1 :(得分:0)
在关于Logger.log的Log4J API中(String callerFQCN,优先级,对象消息,Throwable t):
参数:
请参阅:Log4J API。
我知道很奇怪,参数被称为“callerFQCN”,它接近调用者对象类,但是(muajaja!)它实际上是“包装器”类(来自MyClass.class.getName())。
实际上,我认为调用者是通过Throwable论证获得的。不确定,还没有检查实施。
当你离开Throwable参数为null时,我认为必须在下面发生这样的事情:
StackTraceElement[] stack = (new Throwable()).getStackTrace();
String caller = stack[something, meaby 1].getClassName();
如果要创建Logger包装器,则需要执行以下操作:
public static void myWarn(String message) {
myLogger.log(MyWrapper.class.getName(), message, Level.WARN, null);
}
这项工作没有问题作为包装。
或者,如果您绝对需要维护下面显示的界面,请执行以下操作:
// Warning: Pseudocode
public static void myWarn(Object source, String message) {
String sourceClass = source.class.GetName();
StackTraceElement[] stack = (new Throwable()).getStackTrace();
stack[1, or meaby 2... or 0?] = new whatever(sourceClass);
myLogger.log(MyWrapper.class.getName(), message, Level.WARN, myStack);
}
希望这有帮助。
答案 2 :(得分:0)
这应该这样做:
class Logger2 {
Logger _log4JLogger;
public void log(Object msg) {
_log4JLogger.log(Logger2.class.getName(), Priority.INFO, msg, null);
}
}