【问题标题】:Can I prevent the `java.util.logging.LogManager` from shutting down too quickly?我可以防止 `java.util.logging.LogManager` 过快关闭吗?
【发布时间】:2016-04-03 17:53:28
【问题描述】:

我的 Java 程序在 Linux 上运行,它需要在关闭之前关闭一些文件句柄(实际上是设备),所以我在 JVM 上添加了一个关闭挂钩。但是,我注意到java.util.logging.LogManager 也有一个关闭挂钩,并且它往往会在我关闭之前关闭,这意味着我无法记录有关我的关闭过程的任何内容。

有没有办法阻止 LogManager 安装其关闭挂钩,以便我可以在关闭时执行日志记录,然后在我准备好时告诉它清理?

【问题讨论】:

    标签: java java.util.logging


    【解决方案1】:

    这更像是一种解决方法...但是...由于我在 Linux 上运行(这是一个专用于特定系统的程序),我最终使用sun.misc.Signal 使用信号处理程序。信号处理程序在JVM 运行关闭挂钩之前运行(大概它也有自己的信号处理程序来启动该进程)。

    所以我现在正在这样做,而不是 Runtime.getRuntime().addShutdownHook

    private void installSignalHandlers() {
        SignalHandler signalHandler = signal -> shutDown();
        Signal.handle(new Signal("INT"), signalHandler);
        Signal.handle(new Signal("TERM"), signalHandler);
    }
    

    它似乎工作得很好;在日志记录仍在运行时,我可以关闭 shutDown 中所有打开的句柄等。

    【讨论】:

      【解决方案2】:

      嗯,您可以使用您创建的类的名称来定义系统属性“java.util.logging.manager”。这将允许您使用自己设计的日志管理器。

      https://docs.oracle.com/javase/8/docs/api/java/util/logging/LogManager.html

      我以前从未尝试过这个,所以我不知道它会有多好或有多少工作。

      【讨论】:

      • 我考虑过这个,但看起来确实需要做很多工作。理想情况下,子类化 LogManager 会很好,但它的默认构造函数是添加关闭钩子的地方,没有办法阻止它被调用。
      • 有时为了重新实现一个类,我从 Java API 中复制了整个代码,然后在需要的地方进行了调整。它不漂亮,但它有效。
      • 是的,目前还不清楚 JDK 源代码许可证是否允许我这样做。
      • @tyrel 如果你想阻止 LogManager 安装关闭钩子,你可以安装一个自定义的 SecurityManager,它会在请求权限时抛出 IllegalStateException。但是,您不必阻止安装挂钩。您需要做的就是在 LogManager 子类中覆盖 LogManager.reset。让你的关闭钩子也调用 LogManager.reset 并且只有在你的钩子完成时才允许重置实际做一些事情。
      【解决方案3】:

      使 LogManager 清理线程加入您的关闭挂钩或通过安装自定义处理程序直接执行文件清理。清洁线程将按顺序枚举记录器并尝试关闭附加的处理程序。只要您的处理程序是它尝试关闭的第一个处理程序,您就可以控制清理程序何时执行。

      public class ShutdownHandler extends Handler {
      
          public static void main(String[] args) {
              install();
          }
      
          private static void install() {
              LogManager lm = LogManager.getLogManager();
              Logger first = null;
              ShutdownHandler sh = new ShutdownHandler();
              for (;;) {
                  try {
                      Enumeration<String> e = lm.getLoggerNames();
                      while (e.hasMoreElements()) {
                          first = lm.getLogger(e.nextElement());
                          if (first != null) {
                              break;
                          }
                      }
                      break;
                  } catch (ConcurrentModificationException olderJvm) {
                  }
              }
      
              Logger.getLogger("").addHandler(sh);
              if (first != null) {
                  first.addHandler(sh);
              }
          }
      
          public ShutdownHandler() {
              super.setLevel(Level.ALL);
          }
      
          @Override
          public void publish(LogRecord record) {
          }
      
          @Override
          public void flush() {
          }
      
          @Override
          public void close() throws SecurityException {
              if (!Level.OFF.equals(super.getLevel())) {
                  super.setLevel(Level.OFF);
                  shutDown();
              }
          }
      
          private void shutDown() {
              System.out.println(this + " shutdown by "
                      + Thread.currentThread().getClass().getName());
              //Close your files or join with your other shutdown hook.
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-30
        • 1970-01-01
        • 2022-08-14
        • 1970-01-01
        • 2015-12-06
        • 1970-01-01
        • 1970-01-01
        • 2011-08-01
        相关资源
        最近更新 更多