log4j2 Unable to register shutdown hook because JVM is shutting down

19,089

Solution 1

As explained in Pouriya's answer, you are probably trying to use the Log4j2 when your application is already stopping without a proper shutdown hook. Since you are talking about a Tomcat web application, I assume you are using Servlets. (If you don't, see the second part below). Then, you must declare this in your ContextListener:

public class ContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent evt) {
        String appenderName = evt.getServletContext().getInitParameter("log4jContextName");
        File file = new File(evt.getServletContext().getInitParameter("log4jConfiguration"));
        if(!file.exists()){
            logger = LogManager.getRootLogger();
        } else{
            logger = LogManager.getLogger(appenderName);
        }
    }
}

@Override
public void contextDestroyed(ServletContextEvent evt) {
    // You don't really need to do anything here, about the logger.
    // The log4j2 JAR will handle it properly.
}

As usual with web applications, the Log4J2's config file must be indicated in the web.xml file, as:

<?xml version="1.0" encoding="UTF-8"?>
<web-app ... >
    <context-param>
        <param-name>log4jContextName</param-name>
        <param-value>myApplication</param-value>
    </context-param>

    <context-param>
        <param-name>log4jConfiguration</param-name>
        <param-value>/the/path/to/your/log4j.properties.file</param-value>
    </context-param>
</web-app>

If you are instead using a normal application, then you need to add explicitly your shutdown hook:

public static void main( String[] args ) {

    ...

    File file = new File(logFileName);
    if(!file.exists()){
        logger = LogManager.getRootLogger();
    } else {
        System.setProperty("log4j.configurationFile", file.toURI().toURL().toString());
        logger = LogManager.getLogger("yourProgramName");
    }

    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            logger.info("Shutting down - closing application");
            // Shut down everything (e.g. threads) that you need to.

            // then shut down log4j
            if( LogManager.getContext() instanceof LoggerContext ) {
                logger.debug("Shutting down log4j2");
                Configurator.shutdown((LoggerContext)LogManager.getContext());
            } else
                logger.warn("Unable to shutdown log4j2");

            // logger not usable anymore
            System.out.println("Done.");
        }
    });
}

The shutdown hook will be called when your application is ended (i.e. when calling System.exit(0).

You also need to add this in your Log4J2 config file:

XML version:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration shutdownHook="disable">
...
</Configuration>

Json version:

{"configuration":
    {
        "shutdownHook":"disable",
        ....
    }
}

This will tell Log4j2 that you're handling the shutdown of the Logger yourself.

(Since in a normal application you don't have a web.xml file, you have to retrieve your configuration file in some other way).

Solution 2

If you get that error when stopping the web application it means your hook has not been registered at the right time. By definition it should have been registered before so that it can actually be called during shutdown.

Solution 3

The exception is as a results of a bug reported under ID - LOG4J2-658 in Apache Issues. Last time I checked it was still open.

In the meantime to resolve the challenge add shutdownHook="disable" as an added parameter within your configuration file. This will disable the shutdown hook

Complete format is shown below

<Configuration status="WARN" monitorInterval="30" shutdownHook="disable"> ... </Configuration>

There are a lot of explanation on how shutdown hooks are used and their benefits.

But the short version of it is that Shutdown Hooks are a special construct that allow developers to plug in a piece of code to be executed when the JVM is shutting down. This comes in handy in cases where we need to do special clean up operations in case the VM is shutting down.

As such Log4J2 is trying to use shutdown hook to close the logging service properly, however because of the bug it throws an exception.

Share:
19,089
Grant
Author by

Grant

Student. Like to programming and just started Android programming. Still learning by my own and with your help. :)

Updated on June 04, 2022

Comments

  • Grant
    Grant almost 2 years

    I'm trying to use log4j2 in a tomcat based web application, so I added log4j web module along with other essential jars. However when stopping this web application I'm getting the following exception.

    FATAL Unable to register shutdown hook because JVM is shutting down
    

    Why I'm getting this error and what I can do to prevent this error ?

    Thanks!