Java 自定义记录器 - 没有记录正确的类名

Java Custom Logger - Not logging proper classname

我正在尝试创建自定义记录器。 下面给出了我的代码,下面也给出了Properties文件。

它的工作原理是我以我想要的格式在日志文件中获取日志消息和详细信息。 但是,所有日志都使用相同的类名 - MyLogger 进行记录。我希望我传入构造函数的 'name' 被记录为 ClassName 而不是 MyLogger ClassName。 感谢这方面的任何帮助。

Java代码:

    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 文件内容:

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

--

SimpleFormatter.format 的文档解释说源参数(格式字符串中的 %2$s)是“代表调用者的字符串,如果可用;否则,记录器的名称”。这会查看堆栈以确定直接调用者,在您的情况下,它将始终是 MyLogger class.

要改用记录器名称,请在 java.util.logging.SimpleFormatter.format 配置中使用 %3$s 而不是 %2$s

根据 API 文档,您可以使用 log precise 方法:

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.

将其与 inferCaller 方法相结合,使您的桥看起来透明:

 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);
}

使用此方法,您的代码将找到调用您的桥接记录器的堆栈帧,而不是桥接记录器本身。