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

时间:2010-05-25 14:32:39

标签: java log4j

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

3 个答案:

答案 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);
}

顺便说一句:LevelMDCLogger类都是log4j类。

对评论的回复:

MDC对象存储在ThreadLocal对象上,可供log4j记录器访问。

来自MDC Java文档:

  

MDC是基于每个线程管理的。

答案 1 :(得分:0)

在关于Logger.log的Log4J API中(String callerFQCN,优先级,对象消息,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);
}

希望这有帮助。

答案 2 :(得分:0)

这应该这样做:

class Logger2 {

  Logger _log4JLogger;

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

}