My Java program, which is running on Linux, needs to close some file handles (devices, actually) before it shuts down, so I've got a shutdown hook added on the JVM. However, I noticed that the java.util.logging.LogManager also has a shutdown hook, and it tends to shut down before I have shut down, which means I can't log anything about my shutdown process.
Is there a way to prevent LogManager from installing its shutdown hook so that I can perform logging while shutting down, and then tell it to clean up when I'm ready?
Make the LogManager cleaner thread either join with your shutdown hook or perform your file clean up directly by installing a custom handler. The cleaner thread will enumerate the loggers in order and try to close the attached handlers. As long as your handler is the first one that it tries to close you can control when the cleaner executes.
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) {
}
}
addHandlerFirst(Logger.getLogger(""), sh);
if (first != null) {
addHandlerFirst(first, sh);
}
}
private static void addHandlerFirst(Logger l, Handler h) {
Handler[] handlers = l.getHandlers();
for (int i = handlers.length - 1; i >= 0; --i) {
l.removeHandler(handlers[i]);
}
l.addHandler(h);
for(Handler existing : handlers) {
l.addHandler(existing);
}
}
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.
}
}
Hmm, you could define the system property "java.util.logging.manager" with the name of a class you created. That will allow you to use a logging manager of your own devising.
https://docs.oracle.com/javase/8/docs/api/java/util/logging/LogManager.html
I've never tried this before however so I don't know how well it will work or how much work it'll be.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With