I'm using Spring, and on termination I'm having @PreDestroy clean up beans. I don't understand why logging randomly succeeds sometimes, and fails on others.
// Using Log4j2
Logger log = LogManager.getLogger(MyClass.class);
@PreDestroy
public void close() {
log.warn("Test");
}
Sometimes I will get nothing (no "Test" is logged), other times I will get:
[13:48:44] INFO MyClass: Test
If I include System.out.println("Is this run?");
in the close() method, it will always print.
I'm not actually sure what is happening. I don't know if it's because the JVM is shutting down and the logger is killed... but I thought that would throw some kind of exception?
Note that the logging logs both to a file + stdout, I don't know if that would affect anything. Logging works fine for the other countless thousands of lines of code, but not this.
NOTE: I am open to switching logging libraries if it ends up being this particular library.
EDIT: MyClass would be a bean in a spring.xml document.
Spring Boot uses Commons Logging for all internal logging but leaves the underlying log implementation open. Default configurations are provided for Java Util Logging, Log4J2, and Logback. In each case, loggers are pre-configured to use console output with optional file output also available.
Spring Boot uses Apache Commons Logging for internal logging but allows developers to configure the underlying log implementation. Various logging providers are supported through simple configuration. Spring Boot provides default configurations for Java Util Logging, Log4J2 and Logback.
Spring boot's internal logging provider is Apache Commons which provides support for Java Util Logging ,Log4j2, and Logback.
Spring Boot has a LoggingSystem abstraction that attempts to configure logging based on the content of the classpath. If Logback is available, it is the first choice. You can also set the location of a file to which to write the log (in addition to the console) by using "logging. file".
I think it comes down to this, from Runtime.addShutdownHook:
When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently.
So, as long as LogManager and the Spring IOC container are both shut down by JVM shutdown hooks, there is no way to ensure the message will be recorded. If the LogManager is shut down first, the message is lost. If the IOC container is shut down first, the message is recorded.
If you are running in a JEE container, there's probably little you can do to change this.
However, if you're running in a stand-alone environment, you can add a shutdownHook="disable"
to the Log4j 2 <configuration>
tag. This prevents Log4j 2 from registering it's own shutdown hook. Then, instead of calling ctx.registerShutdownHook()
(the recommended way to shutdown the IOC), you register your own shutdown hook. Something like:
class MyShutdownHook extends Thread {
private AbstractApplicationContext ctx;
public MyShutdownHook(AbstractApplicationContext ctx) {
this.ctx = ctx;
}
public void run() {
ctx.close();
Set<LoggerContext> contexts = new HashSet<>();
for (Logger logger : LoggerContext.getLoggers()) {
contexts.add(logger.getContext());
}
for (LoggerContext ctx : contexts) {
Configurator.shutdown(LogManager.getContext());
}
}
}
AbstractApplicationContext ctx = /* create context */
Runtime.getRunTime().addShutdownHook(new MyShutdownHook(ctx);
Update: Corrected process of shutting down Log4j2.
Caveat: I am away from my usual build machines, so I have not compiled this, but I believe it's hitting the correct APIs.
I dont have enough reputation to add a comment, so i will answer here:
According to the JavaEE API javadoc:
Check if an exception is being thrown somewhere else "silently", that might be one cause.
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