user12384512
user12384512

Reputation: 3401

Pass Logger as argument to another class

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

Answers (2)

Adrian Shum
Adrian Shum

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

Rafal Borowiec
Rafal Borowiec

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

Related Questions