Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to log within shutdown hooks with Log4j2?

Tags:

Log4j2 also uses shutdown hooks to end it's services. But of course I want to log throughout the whole lifecycle of my application - shutdown included. With Log4j this was no problem. Now it seems to be impossible. Logging shuts down, while my application is still working on it. Has anyone some hope for me?

Best regards Martin

like image 550
Martin Avatar asked Jul 01 '13 08:07

Martin


People also ask

How do you use a shutdown hook?

From the surface, using a shutdown hook is downright straightforward. All we have to do is simply write a class that extends the java. lang. Thread class, and provide the logic that we want to perform when the VM is shutting down, inside the public void run() method.

How do you change the log level in log4j2?

You can set a logger's level with the class Configurator from Log4j Core. BUT be aware that the Configurator class is not part of the public API. If you wish to change the root logger level, do something like this : LoggerContext ctx = (LoggerContext) LogManager.

What is root logger in log4j2?

This concept is known as Logger Hierarchy. Logger Hierarchy is made up of set of LoggerConfig objects with a parent-child relationship. The topmost element in every Logger Hierarchy is the Root Logger. If Log4j2 doesn't find the configuration file, only Root Logger will be used for logging with logging level as ERROR.

What is the difference between Log4j and log4j2?

Community support: Log4j 1. x is not actively maintained, whereas Log4j 2 has an active community where questions are answered, features are added and bugs are fixed. Automatically reload its configuration upon modification without losing log events while reconfiguring.


2 Answers

As of 2.0-beta9 this is now configurable in xml

<configuration ... shutdownHook="disable"> 

Considering its now disabled, I guess I need to manually shutdown the logging system at the end of my shutdown hook. However I couldn't find a means thorough the external interface, only in the internal api

import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.LoggerContext; ...  public static void main(String[] args) {     final AnnotationConfigApplicationContext springContext = new AnnotationConfigApplicationContext(AppConfig.class)      Runtime.getRuntime().addShutdownHook(new Thread() {         public void run() {             //shutdown application             LOG.info("Shutting down spring context");             springContext.close();              //shutdown log4j2             if( LogManager.getContext() instanceof LoggerContext ) {                 logger.info("Shutting down log4j2");                 Configurator.shutdown((LoggerContext)LogManager.getContext());             } else                 logger.warn("Unable to shutdown log4j2");         }     });      //more application initialization } 

Update:

There is LogManager.shutdown() method since log4j version 2.6

like image 184
Chomeh Avatar answered Sep 21 '22 08:09

Chomeh


I basically just answered the same question and I tough I'll share my answer here. I encourage you to read the complete answer available here. I'll try to provide a summary here and adapt my answer to the current context.

In the first version, Log4j was providing an API to manually call the shutdown procedure. For reasons we don't have the knowledge of, it was removed from the second version. Now, the right way of doing it (according to the none-existent documentation), is to provide your own implementation of the ShutdownCallbackRegistry interface, which is responsible of the shutdown procedure.

Proposed solution

What I did to fix this issue is that I implemented my own version of the ShutdownCallbackRegistry interface. It mostly does the same things the default implementation does, but instead of registering itself as a shutdown hook to the JVM, it wait until it's invoked manually.

You can find the complete solution and instructions on GitHub/DjDCH/Log4j-StaticShutdown and use it in you own projects. Basically, at the end, you only have to do something like this in your application:

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {     @Override     public void run() {         try {             // Do your usual shutdown stuff here that need logging         } finally {             // Shutdown Log4j 2 manually             StaticShutdownCallbackRegistry.invoke();         }     } })); 

I can't say without any doubt that this is the perfect solution and that my implementation is perfect, but I tried to do it the right way. I'll be glad to hear feedback from you, either if you find this solution appropriate or not.

like image 26
DjDCH Avatar answered Sep 20 '22 08:09

DjDCH