java log4j2 无法注册关闭挂钩,因为 JVM 正在关闭

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30120330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:30:57  来源:igfitidea点击:

log4j2 Unable to register shutdown hook because JVM is shutting down

javalogginglog4japache-commonslog4j2

提问by Grant

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.

我正在尝试在基于 tomcat 的 Web 应用程序中使用 log4j2,因此我添加了 log4j Web 模块以及其他基本 jar。但是,在停止此 Web 应用程序时,出现以下异常。

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!

谢谢!

回答by ocramot

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:

正如在 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.
}

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

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


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

当您的应用程序结束时(即调用System.exit(0).

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

您还需要将其添加到 Log4J2 配置文件中:

XML version:

XML 版本:

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

Json version:

JSON 版本:

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

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

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

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

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

回答by Pouriya Zarbafian

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.

如果您在停止 Web 应用程序时遇到该错误,则意味着您的钩子没有在正确的时间注册。根据定义,它应该在之前已经注册,以便在关闭期间实际调用它。