Java 将记录器作为参数传递给另一个类

Java 将记录器作为参数传递给另一个类,java,logging,log4j,apache-commons-logging,Java,Logging,Log4j,Apache Commons Logging,我希望在日志消息中看到类A,而不是SessionLogger: public class A { private static final Log log = LogFactory.getLog(A.class) public void doIt() { sessionLogger.info(log, "hello world"); } } 在类路径中有commons-logging.jar和log4j-1.2.16.jar。Logger是org.apache.commo

我希望在日志消息中看到类A,而不是SessionLogger:

public class A {
  private static final Log log = LogFactory.getLog(A.class)
  public void doIt() {
     sessionLogger.info(log, "hello world");
  }
}
在类路径中有commons-logging.jar和log4j-1.2.16.jar。Logger是org.apache.commons.logging.Log的一个实例

更新


刚刚发布,这是预期的行为,因为
Logger
记录调用log方法的代码行。因此,应该以另一种方式进行

我认为解决方案是编写一个定制的Log4j模式布局,如本文所示:

这样您就不需要SessionLogger,它将大大简化您的代码

布局:

2013-10-07 00:29:27,328  INFO [main] (SessionLogger.java:17) - SessionId [123]: Hello world
模式分析器:

public class MyPatternLayout extends PatternLayout {

    @Override
    protected PatternParser createPatternParser(String pattern) {
        return new MyPatternParser(pattern);
    }
}
模式转换器:

public class MyPatternParser extends PatternParser {

    private static final char USERNAME_CHAR = 'S';

    public MyPatternParser(String pattern) {
        super(pattern);
    }

    @Override
    protected void finalizeConverter(char c) {
        switch (c) {
            case USERNAME_CHAR:
                currentLiteral.setLength(0);
                addConverter(new MyPatternConverter());
                break;
            default:
                super.finalizeConverter(c);
        }
    }
}
Log4j配置:

public class MyPatternConverter extends PatternConverter {
    @Override
    protected String convert(LoggingEvent event) {
        // Retrieve SessionID
        return "123";
    }
}

在浏览了您想要实现的目标之后,我相信使用MDC可能是一个更合理的选择,而不是使用那些棘手的SessionLogger工具

在MDC中设置会话ID(取决于您的应用程序设计。对于web应用程序,让servlet过滤器执行MDC设置工作是合理的),并让每个人都像平常一样使用记录器。通过使用适当的模式,可以将会话ID放入结果日志消息中

不确定MDC是否在Apache Commons日志中公开,但它在SLF4J或Log4J中可用


好奇的是,有没有理由使用ACL(众所周知,ACL有很多问题)。考虑切换到近年来被广泛采用的SLF4J。

>原因记录器记录代码行,其中调用了日志方法YEP。但也可以记录一行代码。由于log4j调用Thread.currentThread().getStackTrace()。。。为了在运行时获取行号,我不能在这种情况下使用这种方法。感谢共享MDC方法。但它不适合我,因为它依赖于ThreadLocal变量。我想知道为什么依赖ThreadLocal是个问题?除非您正在做一些棘手的多线程工作,否则ThreadLocal很少是一个问题。ThreadLocal的使用量远远超出您的预期,例如在事务管理等方面。是的,有很多多线程、执行者、生产者/消费者等。它不是一个简单的web应用程序。但是,我仍然认为使用MDC是一条路要走。在您最初的方法中,记录器的调用者应该传入会话ID,或者有人需要创建一个具有会话ID的记录器并传递记录器。没有特别的原因,您不能传递会话信息,并在适当的位置执行相应的MDC设置。美妙之处在于,这种MDC设置大多可以隐藏在实际处理逻辑之外(而当前处理逻辑知道会话ID/特殊会话记录器),并且处理逻辑可以执行正常的日志记录。
public class MyPatternConverter extends PatternConverter {
    @Override
    protected String convert(LoggingEvent event) {
        // Retrieve SessionID
        return "123";
    }
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out"/>
        <layout class="MyPatternLayout">
            <param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p (%F:%L) - Session ID:%S %m%n"/>
        </layout>
    </appender>

    <root>
        <priority value ="debug" />
        <appender-ref ref="console" />
    </root>

</log4j:configuration>