Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

log4j2 Unable to register shutdown hook because JVM is shutting down

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!

like image 455
Grant Avatar asked May 08 '15 09:05

Grant


1 Answers

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).

like image 174
ocramot Avatar answered Sep 28 '22 03:09

ocramot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!