使用log4j包装器在日志语句中打印“source”类

我的应用程序有一个自制日志记录类,我正在迁移到使用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 

我的自制日志记录解决方案使用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基于每个线程进行管理。

在关于Logger.log的Log4J API中(String callerFQCN,Priority level,Object message,Throwable t):

参数:

  • callerFQCN – 包装类的完全限定类名。
  • level – 日志记录请求的级别。
  • message – 日志记录请求的消息。
  • t – 日志记录请求的throwable可能为null。

请参阅: 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); } 

希望这可以帮助。

这应该这样做:

 class Logger2 { Logger _log4JLogger; public void log(Object msg) { _log4JLogger.log(Logger2.class.getName(), Priority.INFO, msg, null); } }