Java Logging: show the source line number of the caller (not the logging helper method)

Solution 1:

Alternative answer.

It is possible to ask log4j to exclude the helper class by using the method

Category.log(String callerFQCN, Priority level, Object message, Throwable t)

and specifying the helper class as 'callerFQCN'.

For example here is a class using a helper:

public class TheClass {
    public static void main(String...strings) {
        LoggingHelper.log("Message using full log method in logging helper.");
        LoggingHelper.logNotWorking("Message using class info method");
}}

and the code of the helper:

public class LoggingHelper {
private static Logger LOG = Logger.getLogger(LoggingHelper.class);

public static void log(String message) {
    LOG.log(LoggingHelper.class.getCanonicalName(), Level.INFO, message, null);
}

public static void logNotWorking(String message) {
    LOG.info(message);
} }

The first method will output your expected result.

Line(TheClass.main(TheClass.java:4)) Message using full log method in logging helper.
Line(LoggingHelper.logNotWorking(LoggingHelper.java:12)) Message using class info method

When using this method, Log4j will work as usual, avoiding calculating the stack trace if it is not required.

Solution 2:

Please note that giving the line number is something very costly, either for what you get naturally from Log4j or the following. You have to accept that cost...

You could use the following APIs:

    StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
    StackTraceElement stackTraceElement = ...;
    stackTraceElement.getLineNumber();

Updated:

You would have to calculate it yourself. So:

  • ask log4j not to output it (in your logging format),
  • and insert yourself the line number explicitement in the beginning of your message (the String you send to log4j).

Depending how you prefer your loggers, your helper method may:

  • use an explicit Logger (passed as a parameter I guess), when appropriate (we sometimes define specific loggers for specific context ; for example, we have a logger for sending our database requests, no matter what class does it ; this allow us to reduce to one place the changes made to our configuration file, when we want to (de-)activate them ...)
  • use a Logger for the calling class : in this case, instead of passing the parameter, you can deduce the caller class name likewise...

Solution 3:

Comes out that there is a very simple solution, just add FQCN (The wrapper class' fully qualified class name) to your logger helper:

public class MyLogger extends Logger {

private static final String FQCN = MyLogger.class.getName() + ".";

protected MyLogger(String name) {
    super(name);
}

public void info(final Object msg) {
    super.log(FQCN, Level.INFO, msg, null);
}

//etc...

In Your working class you just do:

public class MyClass {

private static final Logger LOG = MyLogger.getLogger();   

private void test()
{
    LOG.info("test");
}

}