Не удалось установить значения в MDC

Я пытаюсь записать несколько значений в onBeginRequest() из RequestCycle() в калитке. Но значения не регистрируются в файле отладки. Я помещаю значения в MDC в RequestCycleListeners().

Ниже приведен код:

getRequestCycleListeners().add(new AbstractRequestCycleListener()
{       
public void onBeginRequest(RequestCycle cycle) 
{                   
  if( cycle.getRequest().getContainerRequest() instanceof HttpServletRequest )
  {
    HttpServletRequest containerRequest = 
        (HttpServletRequest)cycle.getRequest().getContainerRequest();

    MDC.put("serverName", containerRequest.getServerName());
    MDC.put("sessionId",  containerRequest.getSession().getId());

    LOGGER.debug("logging from RequestCycleListeners() !!!");
    WebClientInfo webClientInfo = new WebClientInfo(RequestCycle.get());
    System.out.println(webClientInfo.getUserAgent());
    System.out.println("webClientInfo.getProperties().getBrowserVersionMajor() " +containerRequest.getRemoteAddr());
}

};

Я ожидаю, что "serverName", "sessionId" будет зарегистрирован в файле отладки.

Я добавил этот listener в класс, который расширяет WebApplication.

Я использую log4j.xml DEBUG appender выглядит следующим образом:

<appender name="DEBUG" class="org.apache.log4j.rolling.RollingFileAppender">
  <param name="Append" value="true"/>
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="[%d{ISO8601} %t %5p] %m -- %X{serverName} -- %X{sessionId} -- %X{portNumber}%n"/>
  </layout>
  <filter class="org.apache.log4j.varia.LevelRangeFilter">
    <param name="LevelMin" value="DEBUG"/>
    <param name="LevelMax" value="WARN"/>
  </filter>
</appender>

и мы определяем область в корневом теге:

<root>
   <priority value="INFO" />
   <appender-ref ref="CONSOLE" />
   <appender-ref ref="DEBUG" />
   <appender-ref ref="ERROR" />
</root>

Ответ 1

Обычно значения MDC выводятся только в журналы, если вы включаете ключи MDC в свой шаблон регистрации через конфигурацию. Поскольку slf4j - это просто фасад, вам нужно иметь поддержку и конфигурацию под фрейм под slf4j, чтобы использовать MDC. Прочитайте записи slf4j на этом здесь.

Итак, например, если вы используете log4j как impl под slf4j, тогда вам понадобится log4j config (ConversionPattern), например:

%d %-5p [%c] [%X{serverName} %X{sessionId}] %m%n

Где %X{serverName} %X{sessionId} - соответствующая часть, которая извлекает значения из MDC.

Здесь довольно хороший пример с использованием log4j без sl4j. См. Примечания к X Символ преобразования в log4j javadoc здесь.

Обратите внимание, что синтаксис шаблона для журнала идентичен. См. Подробности для журнала здесь.

Также обратите внимание, что наилучшая практика для MDC (использующая ThreadLocal под капотом) заключается в очистке контекста (удаление значений, которые вы помещаете на карту), когда контекст больше не находится в области видимости. Это обычно означает вызов remove или clear в блоке finally, например:

try {
    //...
    MDC.put("key1", value1);
    MDC.put("key2", value2);
    //...
} finally {
    //this
    MDC.remove("key1");
    MDC.remove("key2");
    //or this
    MDC.clear();
}

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

ИЗМЕНИТЬ

Ваша конфигурация log4j кажется немного странной по следующим причинам:

  • Вы называете свои приложения после уровня журнала, что может вызвать путаницу.
  • Ваш RollingFileAppender не определяет файл
  • Ваш журнал root будет регистрироваться в 3 разных приложениях, один из которых имеет имя DEBUG, но он настроен только на уровень log INFO и больше (на основе тега priority), поэтому отладочные утверждения не будет регистрироваться

Если у вас нет определенных категорий, настроенных отдельно, которые не отображаются, я бы предположил, что ни один из ваших операторов LOGGER.debug не регистрируется, независимо от попытки использования MDC.

Ответ 2

Обратите внимание: если вы используете AsyncAppender, очистка MDC из вашего потока не будет защищать вас, так как обработка журнала и обработка MDC происходят в потоке AsyncAppender. См. Также эта связанная ошибка

К сожалению, в версии v 1.2.17 последней выпущенной версии EOLed log4j-1.x Dispatcher-Thread AsyncAppender не очищает MDC после остановки.

Так как AsyncAppender/Dispatcher довольно прост, его легко исправить, поставив

finally
{
    MDC.clear();
}

в try-блоке в org.apache.log4j.AsyncAppender.Dispatcher.run().

Конечно, это также можно обойти это, не используя AsyncAppender при выполнении в ServletContainer.