Условное ведение журнала с log4j - PullRequest
19 голосов
/ 13 сентября 2011

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

Ответы [ 4 ]

19 голосов
/ 13 сентября 2011

Вы хотите посмотреть Вложенные диагностические контексты или Сопоставленные диагностические контексты в 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 {ключ} выводит значение MDC.get (ключ) в MDC.Если вам нужен более сложный фильтр, вы можете расширить его самостоятельно и посмотреть значения в MDC самостоятельно.

7 голосов
/ 15 сентября 2011

Ответ Мэтью Фарвелла (используйте MDC) мне помог, и он упоминает о написании вашего собственного фильтра. В некоторых случаях мне нужно было скрывать сообщения регистрации. В частности, у нас есть вызов проверки работоспособности, который срабатывает гораздо чаще, чем при обычном использовании пользователем, и он заполнял журналы без необходимости. Решение Мэтью не подходит к моей ситуации, потому что оно требует, чтобы вы добавили 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
}
1 голос
/ 13 сентября 2011

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

0 голосов
/ 05 октября 2016

Я делаю обходной путь, как следует

Сконфигурируйте свою цель журнала в 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")

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...