AKPuvvada
AKPuvvada

Reputation: 65

Java Custom Logger - Not logging proper classname

I am trying to create a Custom Logger. My code is given below and the Properties file is also given below.

It works in the sense that I get log messages and details in the log file in the format I want. However, all logs are logged with same ClassName - MyLogger. I want the 'name' I am passing in the constructor to be logged as ClassName instead of the MyLogger ClassName. Appreciate any help in that regard.

Java Code:

    public class MyLogger {

    private static Logger log;
    
    public static MyLogger getLogger(String name) {
        return new MyLogger(name);
    }

    private MyLogger(String name) {
        log = Logger.getLogger(name);
        try {
            LogManager.getLogManager().readConfiguration(new FileInputStream("./logging.properties"));
        } catch (FileNotFoundException ex) {
            Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException | SecurityException ex) {
            Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void log(Level LogLevel, String logMessage, Object param1) {
        log.log(LogLevel, logMessage, param1);
    }

    public void log(Level LogLevel, String logMessage, Throwable e) {
        log.log(LogLevel, logMessage, e);
    }

    public void log(Level LogLevel, String logMessage) {
        log.log(LogLevel, logMessage);
    }
}

logging.properties File content:

handlers = java.util.logging.FileHandler
java.util.logging.FileHandler.level     = ALL
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format = %1$tF %1$tT %4$s %2$s %5$s%6$s%n
java.util.logging.FileHandler.limit     = 1048576
java.util.logging.FileHandler.count     = 5
java.util.logging.FileHandler.append    = true
java.util.logging.FileHandler.pattern   = ./logs/log-%u-%g.log

--

Upvotes: 1

Views: 1137

Answers (2)

jmehrens
jmehrens

Reputation: 11085

Per API docs you can use the log precise methods:

There are a set of "logp" methods (for "log precise") that are like the "log" methods, but also take an explicit source class name and method name.

Combine that with the inferCaller method to make your bridge look transparent:

 public void log(Level LogLevel, String logMessage) {
    StackTraceElement stack = inferCaller();
    log.logp(stack.getClassName(), stack.getMethodName(), LogLevel, logMessage);
 }

private boolean isPrintImplFrame(String cname) {
    return MyLogger.class.getName().equals(cname);
}

private StackTraceElement inferCaller() {
    StackTraceElement stack[] = (new Throwable()).getStackTrace();
    int ix = 0;
    while (ix < stack.length) {
        StackTraceElement frame = stack[ix];
        String cname = frame.getClassName();
        if (isPrintImplFrame(cname)) {
            break;
        }
        ix++;
    }

    while (ix < stack.length) {
        StackTraceElement frame = stack[ix];
        String cname = frame.getClassName();
        if (!isPrintImplFrame(cname)) {
            return frame;
        }
        ix++;
    }

    return new StackTraceElement(MyLogger.class.getName(), "log",
            MyLogger.class.getName(), -1);
}

Using this method your code will find the stack frame that is calling your bridge logger that is not the bridge logger itself.

Upvotes: 1

Tim Moore
Tim Moore

Reputation: 9492

The documentation for SimpleFormatter.format explains that the source parameter (%2$s in the format string) is "a string representing the caller, if available; otherwise, the logger's name". This looks at the stack to determine the direct caller, which in your case will always be the MyLogger class.

To use the logger name instead, use %3$s in the java.util.logging.SimpleFormatter.format configuration rather than %2$s.

Upvotes: 4

Related Questions