Нет вывода журнала в contextDestroyed с использованием ServletContextListener & SLF4J

Я пытаюсь написать сообщение в журнал, что сервлет (Vaadin) остановился, используя SLF4J и Log4j2.

Для этого я использую ServletContextListener который регистрирует сообщение при запуске приложения. Однако я не смог получить никакого вывода при входе в систему contextDestroyed метод... Вот моя реализация:

@WebListener
public class VaadinLogger implements ServletContextListener {

    private static final Logger logger = LoggerFactory.getLogger(VaadinLogger.class);

    @Override
    public void contextInitialized(ServletContextEvent contextEvent) {
        // Remove appenders from JUL loggers
        SLF4JBridgeHandler.removeHandlersForRootLogger();

        // Install bridge
        SLF4JBridgeHandler.install();

        // Get servlet context
        ServletContext context = contextEvent.getServletContext();

        // Retrieve name
        String name = context.getServletContextName();

        // Log servlet init information
        logger.info("Start \"{}\"", name);
    }

    @Override
    public void contextDestroyed(ServletContextEvent contextEvent) {
        // Get servlet context
        ServletContext context = contextEvent.getServletContext();

        // Retrieve name
        String name = context.getServletContextName();

        // Log servlet destroy information
        logger.info("End \"{}\"{}", name, System.lineSeparator()));

        // Uninstall bridge
        SLF4JBridgeHandler.uninstall();
    }
}

На данный момент, я предполагаю, что это, вероятно, потому что в точке contextDestroyed вызывается, регистрация больше невозможна, потому что они уже были уничтожены сборщиком мусора.

Итак, теперь мой вопрос: возможно ли либо зарегистрировать, что сервлет остановился до уничтожения контекста, либо заставить работать contextlistener до уничтожения регистраторов log4j2?

Заранее спасибо!

3 ответа

Начиная с log4j 2.14.1, вы можете отключить автоматическое выключение и добавить прослушиватель для остановки регистратора.

      <context-param>
    <!-- auto-shutdown stops log4j when the web fragment unloads, but that
         is too early because it is before the listeners shut down. To 
         compensate, use a Log4jShutdownOnContextDestroyedListener and
         register it before any other listeners which means it will shut
         down *after* all other listeners. -->
    <param-name>isLog4jAutoShutdownDisabled</param-name>
    <param-value>true</param-value>
</context-param>    

<listener>
   <!-- ensure logging stops after other listeners by registering
        the shutdown listener first -->
    <listener-class>
       org.apache.logging.log4j.web.Log4jShutdownOnContextDestroyedListener
    </listener-class>
</listener>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

Во-первых, есть ли в вашем classpath файлы log4j 2.x api, core и web jar? Log4j-web-2.x.jar также регистрирует прослушиватель контекста, используемый для выключения подсистемы ведения журнала при выгрузке веб-приложения.

Если ваш слушатель запустится после этого, вы больше не сможете ничего записывать.

Вы можете проверить, что происходит, установив <Configuration status="trace" ... в вашем файле конфигурации log4j2.

log4j2 (log4j-web-xx.jar) поставляется с веб-фрагментом. Этот фрагмент содержит ServletContextListener. Порядок слушателей зависит от инициализации (см. Спецификация сервлета). По умолчанию: сначала ваше приложение, потом другие.

Вы можете изменить порядок, чтобы указать <absolut-ordering> в вашем web.xml:

<web-app>
  <absolute-ordering>
    <name>log4j</name>
    <others/>
  </absolute-ordering>

Смотрите также: сервлет-30-веб-фрагмент xml

Другие вопросы по тегам