0
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

我在类路径中有 commons-logging.jar 和 log4j-1.2.16.jar。Logger 是 org.apache.commons.logging.Log 的一个实例

更新

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

4

2 回答 2

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>
于 2013-10-06T21:44:13.237 回答
1

After a glance on what you are trying to achieve, I believe instead of doing that piece of tricky SessionLogger stuff, using MDC may be a more reasonable choice.

Setup the session ID in MDC (depends on your app design. For web app, having an servlet filter doing the MDC setup work is reasonable), and let everyone simply use the logger as normal. By having an appropriate pattern, you can put the session ID in the result log message.

Not sure if MDC is exposed in Apache Commons Logging, but it is available in SLF4J or Log4J.

Just curious, is there any reason to use ACL (which is known to have quite a lot of problem). Consider switching to SLF4J which is more widely-adopted in recent years.

于 2013-10-07T04:26:27.607 回答