简体   繁体   English

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

[英]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.我正在尝试在基于 tomcat 的 Web 应用程序中使用 log4j2,因此我添加了 log4j Web 模块以及其他基本 jar。 However when stopping this web application I'm getting the following exception.但是,当停止此 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!谢谢!

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.正如在 Pouriya 的回答中所解释的那样,当您的应用程序在没有正确关闭挂钩的情况下已经停止时,您可能正在尝试使用 Log4j2。 Since you are talking about a Tomcat web application, I assume you are using Servlets.由于您在谈论 Tomcat Web 应用程序,因此我假设您使用的是 Servlet。 (If you don't, see the second part below). (如果没有,请参阅下面的第二部分)。 Then, you must declare this in your ContextListener:然后,您必须在 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 (ie 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 文件,您必须以其他方式检索您的配置文件)。

If you get that error when stopping the web application it means your hook has not been registered at the right time.如果您在停止 Web 应用程序时遇到该错误,则表示您的钩子未在正确的时间注册。 By definition it should have been registered before so that it can actually be called during shutdown.根据定义,它应该在之前已经注册,以便在关闭期间实际调用它。

The exception is as a results of a bug reported under ID - LOG4J2-658 in Apache Issues.例外是由于在 Apache 问题中的 ID - LOG4J2-658 下报告的错误的结果。 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.在此期间解决挑战添加shutdownHook="disable"作为配置文件中的附加参数。 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.但简而言之,Shutdown Hooks 是一种特殊的结构,允许开发人员插入一段代码,以便在 JVM 关闭时执行。 This comes in handy in cases where we need to do special clean up operations in case the VM is shutting down.如果我们需要在 VM 关闭时执行特殊的清理操作,这会派上用场。

As such Log4J2 is trying to use shutdown hook to close the logging service properly, however because of the bug it throws an exception.因此,Log4J2 尝试使用关闭挂钩来正确关闭日志记录服务,但是由于该错误,它会引发异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM