Reputation: 65
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
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
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