【问题标题】:add Handler to every Logger将处理程序添加到每个记录器
【发布时间】:2015-11-05 18:41:10
【问题描述】:

我想为我项目的每个类的每个记录器添加一个自定义处理程序。我有一个 logging.properties 文件,一开始就使用:

try (InputStream in = ReportingService.class.getResourceAsStream("logging.properties")) {
    LogManager.getLogManager().readConfiguration(in);
} catch (IOException ex) {
    Logger.getLogger(myClass.class.getName()).log(Level.SEVERE, null, ex);
}

logging.properties 文件如下所示:

handlers=java.util.logging.ConsoleHandler,myPackage.AlertHandler
.level=SEVERE
java.util.logging.ConsoleHandler.level=SEVERE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
myPackage.AlertHandler.level=SEVERE
myPackage.AlertHandler.formatter=java.util.logging.SimpleFormatter

而 myPackage.AlertHandler.java 看起来像这样:

package myPackage;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import javafx.scene.control.Alert;
public class AlertHandler extends Handler {
    @Override
    public void publish(LogRecord lr) {
        Alert a = new Alert(Alert.AlertType.ERROR);
        a.setTitle("Exception!");
        a.setHeaderText("Exception was thrown, here is the StackTrace:");
        a.setContentText(getFormatter().formatMessage(lr));
        Platform.runLater(()->{a.showAndWait();});
    }
    @Override
    public void flush() {
        //no real handler is open, nothing to flush
    }
    @Override
    public void close() throws SecurityException {
        //no real handler is open, nothing to close
    }
}

读取日志文件没有问题,因为控制台不再打印 INFO 或 WARNING 消息,只有 SEVERE。但是我的自定义处理程序永远不会被调用,因为没有打开任何警报窗口。我还尝试将处理程序添加到全局记录器,希望每个其他记录器都继承其处理程序,但它也不起作用:

Logger.getGlobal().addHandler(new AlertHandler());
Logger.getLogger("").addHandler(new AlertHandler());

将处理程序添加到特定记录器可以按预期工作:如果在类中的任何位置引发错误,则会打开一个带有堆栈跟踪的警报窗口。

Logger.getLogger("mySecondClass").addHandler(new AlertHandler());

但我想将此处理程序添加到任何类中的每个记录器!

【问题讨论】:

    标签: java logging java-8 java.util.logging


    【解决方案1】:

    但我想将此处理程序添加到任何类中的每个记录器!

    如果您希望此处理程序查看所有记录器输出,那么您只需在根记录器上安装一个实例。例如,Logger.getLogger("").addHandler(new AlertHander());

    默认情况下,子记录器会将日志记录发布到parent handers

    主要问题是您的代码将始终生成 NullPointerException,因为您从未指定要与处理程序一起使用的格式化程序。所以对 getFormatter 的调用将返回 null 然后失败。

    public static void main(String[] args) {
        Handler h = new Handler() {
    
            @Override
            public void publish(LogRecord record) {
            }
    
            @Override
            public void flush() {
            }
    
            @Override
            public void close() throws SecurityException {
            }
        };
        System.out.println(h.getFormatter());
    }
    

    您还需要:

    1. 添加代码以解析日志管理器为您的处理程序分配的级别、格式化程序和过滤器。
    2. 在未定义级别、格式化程序或过滤器值时选择合理的默认值。
    3. 处理非JavaFX Application Threads 使用Platform.runLater 创建和显示对话框。
    4. 在您的发布方法中调用 isLoggable 以确定您的处理程序是否应该发布。
    5. 在您的发布方法中捕获运行时异常并通过调用 Handler.reportError 跟踪它们。

    让生活变得轻松并创建单元测试,以确保您的处理程序在您尝试在野外使用它之前确实有效。

    【讨论】:

    • 好吧,当我手动将它添加到某个记录器时它可以工作,比如: Logger.getLogger("mySecondClass").addHandler(new AlertHandler()); ...当该类中的任何地方抛出异常时,会打开一个警报窗口,所以我很确定 Handler 工作正常!
    • 你确定 Handler 可以工作,但是 javac 说这个例子不能编译。 error: cannot find symbol a = new Alert(Alert.AlertType.ERROR); symbol: variable a 我的意见似乎对 javac 没有影响。单元测试真的会帮助你。
    • 抱歉,这是一个复制和粘贴错误-.-。起初我将 Alert 作为类字段,而不是局部变量^^ 在问题中修复它!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    • 2017-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多