2016-04-03 2 views
0

Моя программа Java, работающая под Linux, должна закрыть некоторые дескрипторы файлов (устройства, на самом деле), прежде чем она выключится, поэтому у меня на JVM добавлен крюк отключения. Тем не менее, я заметил, что у java.util.logging.LogManager также есть крюк отключения, и он, как правило, отключается, прежде чем я выключу, что означает, что я не могу ничего записать о моем завершении процесса.Могу ли я предотвратить слишком быстрое закрытие `java.util.logging.LogManager`?

Есть ли способ предотвратить запуск LogManager своего затвора отключения, чтобы я мог выполнять протоколирование при выключении, а затем сказать, что он будет очищен, когда я буду готов?

ответ

0

Хмм, вы можете определить системное свойство «java.util.logging.manager» с именем созданного вами класса. Это позволит вам использовать диспетчер регистрации вашего собственного проекта.

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

Я никогда не пробовали это раньше, однако, так что я не знаю, насколько хорошо она будет работать или сколько работы будет.

+0

Я рассмотрел это, но похоже, что это будет очень много работы. В идеале подклассификация LogManager была бы приятной, но ее конструктор по умолчанию - это то, где добавлен крюк остановки, без возможности предотвратить его вызов. – tyrel

+0

Иногда, чтобы повторно реализовать класс, я скопировал весь код из Java API, а затем просто сделал твики, где мне было нужно. Это некрасиво, но это работает. – markspace

+0

Да, неясно, позволит ли мне лицензия на исходный код JDK. – tyrel

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, пока ведение журнала все еще работает.

0

Сделайте очистительную нить 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. 
    } 
} 
Смежные вопросы