将Logger作为参数传递给另一个类

时间:2013-10-06 20:36:01

标签: java logging log4j apache-commons-logging

public class SessionLogger {

    private final String sessionId;

    public SessionLogger(String sessionId) {
        this.sessionId = sessionId;
    }

    public void info(Log log, String message, Object... args) {
        log.info(formatMessage(message, args));
    }

    public void error(Log log, String message, Throwable t, Object... args) {
        log.error(formatMessage(message, args), t);
    }

    private String formatMessage(String message, Object... args) {
        for (int i = 0; i < args.length; i++) {
            message = message.replaceFirst("\\{\\}", args[i].toString());
        }
        return String.format("SessionId [%s]: %s", sessionId, message);
    }
}

我想要做的是将Logger实例传递给SessionLogger类,我希望看到类名,Logger初始化。

public class A {
  private static final Log log = LogFactory.getLog(A.class)
  public void doIt() {
     sessionLogger.info(log, "hello world");
  }
}

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

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

我在classpath中有commons-logging.jar和log4j-1.2.16.jar。 Logger是org.apache.commons.logging.Log

的一个实例

更新

刚刚发布它是预期的行为,导致Logger记录代码行,其中调用了log方法。所以它应该以某种方式以另一种方式完成

2 个答案:

答案 0 :(得分:1)

我认为解决方案是编写本文中提供的自定义Log4j模式布局:http://fw-geekycoder.blogspot.com/2010/07/creating-log4j-custom-patternlayout.html

然后您将不需要SessionLogger,这将显着简化您的代码。

布局:

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

模式转换器:

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

Log4j配置:

<?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>

答案 1 :(得分:1)

在看了一下你想要实现的目标后,我相信使用MDC而不是做那件棘手的SessionLogger,可能是一个更合理的选择。

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

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

好奇,有没有理由使用ACL(已知有很多问题)。考虑转换到近年来更广泛采用的SLF4J。