Подтвердить что ты не робот

Условное ведение журнала с помощью log4j

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

Есть ли способ, с помощью которого log4j можно записывать условно? Другими словами, я хотел бы иметь возможность получать журналы трассировки только тогда, когда конкретные пользователи делают запрос. Поскольку я не знаю заранее, какие пользователи будут затронуты, я не могу просто временно жестко записать имена пользователей.

Edit:

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

Logger logger = Logger.getLogger("foo");
String usernameFilter = "piglet";
String username = request.getParameter("username");
logger.setLevel(usernameFilter.equals(username) ? Level.TRACE : Level.INFO);
if (logger.isTraceEnabled()) {
   logger.trace("blah blah blah");
}

Трудность динамически изменяет условие, устанавливающее уровень журнала. Другими словами, в приведенном выше примере, как я могу установить значение usernameFilter, кроме жесткого кодирования.

4b9b3361

Ответ 1

Вы хотите посмотреть Вложенные диагностические контексты или Отображаемые диагностические контексты в log4j или slf4j. NDC/MDC позволяет вставлять данные в ваш сеанс, которые можно фильтровать с помощью log4j.

Итак, вы должны определить имя пользователя в NDC, а затем вы можете изменить log4j.properties, чтобы изменить уровень ведения журнала для определенных пользователей.

MDC использует карту, тогда как NDC основан на принципе стека. Если вы используете slf4j, вы даже можете создавать отдельные файлы журналов в зависимости от информации в вашем MDC.

Например, мы сделали это, когда пользователи вошли в веб-сайт. Мы хотели отслеживать то, что делал конкретный пользователь (ретроспективно), поэтому мы добавили имя пользователя и идентификатор сеанса в NDC, а затем можем отправить фильтр на них.

Код был похож на следующий:

public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        MDC.put("username", session.getParameter("username")); // or where ever t is stored
        chain.doFilter(request, response);
    }
}

В вашем файле log4j.xml эти фильтры основаны на пользователе:

  <appender name="UserDebug" class="org.apache.log4j.RollingFileAppender">
    <param name="File" value="userdebug.log"/>
    <param name="Append" value="true"/>
    <param name="MaxFileSize" value="5000KB"/>
    <param name="maxBackupIndex" value="5"/> 
          <layout class="org.apache.log4j.PatternLayout">
                  <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] user:%X{username} %-5p - %m%n" />
          </layout>

          <filter class="org.apache.log4j.varia.StringMatchFilter">
                  <param name="StringToMatch" value="user:fred" />
                  <param name="AcceptOnMatch" value="true" />
          </filter>

      <filter class="org.apache.log4j.varia.DenyAllFilter"/>
  </appender>

% X {key} выводит значение MDC.get(ключ) в MDC. Если вам нужен более сложный фильтр, вы можете его расширить и посмотреть на значения в MDC самостоятельно.

Ответ 2

Ответ Мэтью Фарвелла (использование MDC) - это тот, который работал у меня, и он упоминает о написании собственного фильтра. Моя потребность заключалась в том, чтобы скрыть протоколирование сообщений в определенных случаях. В частности, у нас есть вызов проверки работоспособности, который встречается гораздо чаще, чем обычное использование пользователей, и он заполняет журналы без необходимости. Решение Matthew не подходит для моей ситуации, потому что для этого требуется добавить MDC к фактическому выходному журналу. Я только хочу использовать MDC для фильтрации, поэтому я расширил org.apache.log4j.spi.Filter следующим классом:

/**
 * Log4J filter that stops certain log messages from being logged, based on a
 * value in the MDC (See Log4J docs).
 */
public class Log4JMDCFilter extends Filter
{

private String keyToMatch;
private String valueToMatch;
private boolean denyOnMatch = true;

/**
 * {@inheritDoc}
 */
public int decide(LoggingEvent event)
{
    if (keyToMatch != null && valueToMatch != null
        && valueToMatch.equals(event.getMDC(keyToMatch)))
    {
        return denyOnMatch ? DENY : ACCEPT;
    }

    return denyOnMatch ? ACCEPT : DENY;
}

/**
 * The key on which to filter.
 * 
 * @return key on which to filter
 */
public String getKeyToMatch()
{
    return keyToMatch;
}

/**
 * Sets the key on which to filter.
 * 
 * @param keyToMatch key on which to filter
 */
public void setKeyToMatch(String keyToMatch)
{
    this.keyToMatch = keyToMatch;
}

/**
 * Gets the value to match.
 * 
 * @return the value to match.
 */
public String getValueToMatch()
{
    return valueToMatch;
}

/**
 * Sets the value to match.
 * 
 * @param valueToMatch the value to match.
 */
public void setValueToMatch(String valueToMatch)
{
    this.valueToMatch = valueToMatch;
}

/**
 * Returns true if the log message should not be logged if a match is found.
 * 
 * @return true if the log message should not be logged if a match is found.
 */
public boolean isDenyOnMatch()
{
    return denyOnMatch;
}

/**
 * Set this to "true" if you do not want log messages that match the given
 * key/value to be logged. False if you only want messages that match to be
 * logged.
 * 
 * @param denyOnMatch "true" if you do not want log messages that match the
 *        given key/value to be logged. False if you only want messages that
 *        match to be logged.
 */
public void setDenyOnMatch(String denyOnMatch)
{
    this.denyOnMatch = Boolean.valueOf(denyOnMatch).booleanValue();
}

}

Используйте следующий фрагмент log4j.xml для активации фильтра ( "HEALTHCHECK" - это ключ, а "true" - это значение, которое я фильтрую):

    <filter class="com.copart.hh.core.utils.Log4JMDCFilter">
        <param name="keyToMatch" value="HEALTHCHECK" />
        <param name="valueToMatch" value="true" />
        <param name="denyOnMatch" value="true" />
    </filter>

Затем в любом месте, которое вы хотите отметить для фильтрации, введите код следующим образом:

MDC.put("HEALTHCHECK", "true");
try
{    
      // do healthcheck stuff that generates unnecessary logs
}
finally
{
    MDC.remove("HEALTHCHECK"); // not sure this is strictly necessary
}

Ответ 3

Я нашел эту статью статью в блоге очень полезной. Это может помочь вам создать условия для регистрации для ваших пользователей.

Ответ 4

Я делаю обходное решение, как следует

Конфигурируйте свой лог файл в файле log4j.xml следующим образом:

    <appender name="file" class="org.apache.log4j.RollingFileAppender">
    <param name="file" value="${catalina.home}/logs/uploader.log" />
    <param name="append" value="false" />
    <param name="threshold" value="info" />
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{1}] - %m%n" />
    </layout>

    <filter class="org.apache.log4j.varia.StringMatchFilter">
        <param name="StringToMatch" value="trackfile" />
        <param name="AcceptOnMatch" value="true" />
    </filter>

     <filter class="org.apache.log4j.varia.DenyAllFilter" />   
</appender>

создать метод журнала клиента, который добавляет целевой тег [ trackfile]

private void logfile(String msg) {
    logger.info("trackfile: " + msg);
}

зарегистрируйте свою информацию, используя вышеуказанный метод:

logfile("your log message")

введите описание изображения здесь