log4j2无法注册shutdown hook,因为JVM正在关闭

时间:2015-05-08 09:26:44

标签: java logging log4j apache-commons log4j2

我正在尝试在基于tomcat的Web应用程序中使用log4j2,所以我添加了log4j web模块以及其他必需的jar。但是,当停止此Web应用程序时,我得到以下异常。

FATAL Unable to register shutdown hook because JVM is shutting down

为什么我收到此错误以及如何防止此错误?

谢谢!

3 个答案:

答案 0 :(得分:9)

正如Pouriya的回答所解释的那样,当你的应用程序在没有正确关闭挂钩的情况下停止时,你可能正在尝试使用Log4j2。 由于您在谈论Tomcat Web应用程序,我假设您正在使用Servlet。 (如果没有,请参阅下面的第二部分)。然后,您必须在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.
}

与Web应用程序一样,Log4J2的配置文件必须在web.xml文件中指明,如下所示:

<?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>

如果您使用普通应用程序,则需要明确添加关闭钩子:

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.");
        }
    });
}

应用程序结束时(即调用System.exit(0)时会调用关闭挂钩。

您还需要在Log4J2配置文件中添加它:

XML版本:

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

Json版本:

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

这将告诉Log4j2您正在自己处理Logger的关闭。

(因为在普通应用程序中,您没有web.xml文件,所以必须以其他方式检索配置文件。)

答案 1 :(得分:3)

如果在停止Web应用程序时遇到该错误,则表示您的挂钩尚未在正确的时间注册。根据定义,它应该在之前注册,以便在关闭期间实际调用它。

答案 2 :(得分:2)

该异常是由于在Apache Issues中的ID-LOG4J2-658下报告​​的错误导致的。上次我检查它是否仍然打开。

在此期间,要解决挑战,请在配置文件中添加 shutdownHook =“ disable” 作为添加的参数。这将禁用关机钩子

完整格式如下所示

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

关于如何使用关闭挂钩及其好处有很多解释。

但是它的简短版本是Shutdown Hooks是一个特殊的结构,允许开发人员插入要在JVM关闭时执行的一段代码。如果需要在VM关闭的情况下进行特殊清理操作,这将派上用场。

因此Log4J2试图使用shutdown钩子来正确关闭日志记录服务,但是由于该错误,它将引发异常。

相关问题