Reputation: 3401
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);
}
}
What I want to do is to pass, Logger instance to the SessionLogger class and I would like to see the class name, where Logger was initialized.
public class A {
private static final Log log = LogFactory.getLog(A.class)
public void doIt() {
sessionLogger.info(log, "hello world");
}
}
I would expect to see class A in the log message instead of SessionLogger:
2013-10-07 00:29:27,328 INFO [main] (SessionLogger.java:17) - SessionId [123]: Hello world
I've commons-logging.jar and log4j-1.2.16.jar in classpath. Logger is an instance of org.apache.commons.logging.Log
Update
Just released that it is expected behavior, cause Logger
logs the line of the code, where log method was invoked. So it should be done another way somehow
Upvotes: 0
Views: 3273
Reputation: 40036
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.
Upvotes: 1
Reputation: 5244
I think the solution is to write a custom Log4j pattern layout as presented in this article: http://fw-geekycoder.blogspot.com/2010/07/creating-log4j-custom-patternlayout.html
Then you will not need SessionLogger, which will simplify your code significantly.
Layout:
public class MyPatternLayout extends PatternLayout {
@Override
protected PatternParser createPatternParser(String pattern) {
return new MyPatternParser(pattern);
}
}
Pattern parser:
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);
}
}
}
Pattern converter:
public class MyPatternConverter extends PatternConverter {
@Override
protected String convert(LoggingEvent event) {
// Retrieve SessionID
return "123";
}
}
Log4j configuration:
<?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>
Upvotes: 1