Spring @PreDestroy: No logging because Logback stops too soon

好久不见. 提交于 2020-01-03 08:25:10

问题


In my project, I am using Logback as logging facility. I have the following class

@Component
class Test {
    @PreDestroy
    public void destroy() {
        try {
            ...
        } catch (Exception e) {
            LoggerFactory.getLogger(getClass()).error(e.getLocalizedMessage(), e);
        }
    }
}

Now, I undeploy the servlet. When an exception occurs, Logback is not printing the message and stack trace. This is because Logback is cleaning up before the destroy() is called by Spring. When undeploying the servlet, this is the first (and last) log line:

15:46:19,084 |-INFO in ch.qos.logback.classic.servlet.LogbackServletContextListener@7957fe56 - About to stop ch.qos.logback.classic.LoggerContext [default]

I verified that Logback stops first by adding a System.out.println("..."); in the destroy().

Is there any way to fix this?

My dependencies:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>5.0.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>99-empty</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-access</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jcl</artifactId>
    </dependency>
</dependencies>

Please note that spring-jcl is used to route commons-logging to slf4j (which will route to logback). I am not using jcl-over-slf4j.


回答1:


There is a documented way to disable to disable the registering of the LogbackServletContextListener:

You may disable the automatic the installation of LogbackServletContextListener by setting a named logbackDisableServletContainerInitializer in your web-application's web.xml file. Here is the relevant snippet.

<web-app>
    <context-param>
        <param-name>logbackDisableServletContainerInitializer</param-name>
        <param-value>true</param-value>
    </context-param>
    .... 
</web-app>

Note that logbackDisableServletContainerInitializer variable can also be set as a Java system property an OS environment variable. The most local setting has priority, i.e. web-app first, system property second and OS environment last.

I would imagine you'll probably want to write your own shutdown hook if this is the case and stop the LoggerContext




回答2:


To pick up Dovmo's answer. It's all about ordering. I have the same issue on Tomcat 8.5.x. Bacially, the initializer does an addListener, you don't have any control over the listener. At shutdown, Tomcat reverse-iterates that list, picking the Logback listener first: Spring won't log anything.

A custom listener won't help because you cannot prepend it. What works for me on Tomcat is:

<listener>
    <listener-class>ch.qos.logback.classic.servlet.LogbackServletContextListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>logbackDisableServletContainerInitializer</param-name>
    <param-value>true</param-value>
</context-param>


来源:https://stackoverflow.com/questions/47184045/spring-predestroy-no-logging-because-logback-stops-too-soon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!