我正在开发的web应用程序偶尔会为一些用户开发数据完整性问题。我想打开跟踪级别日志记录,但由于我们每秒要处理100个请求,跟踪日志记录每个请求都是不可能的。
有没有办法使log4j能够有条件地进行日志记录?换句话说,我希望只有在特定用户发出请求时才能获得跟踪日志。因为我事先不知道哪些用户会受到影响,所以我不能简单地临时硬编码用户名。
编辑:
我想我需要说得更清楚一点。我可以很容易地向我的日志语句中添加条件。例如
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的值,而不是对它进行硬编码。
发布于 2011-09-13 23:32:09
您希望在log4j或slf4j中查看Nested Diagnostic Contexts或Mapped Diagnostic Contexts。NDC/MDC允许您将数据插入到可由log4j过滤的会话中。
因此,您可以将用户名定义为在NDC中,然后可以更改log4j.properties以更改特定用户的日志记录级别。
MDC使用Map,而NDC基于堆栈原则。如果您使用的是slf4j,您甚至可以根据MDC中的信息创建单独的日志文件。
例如,当用户登录到网站时,我们就这样做了。我们想要跟踪某个特定用户正在做什么(回溯),所以我们将用户名和会话id添加到NDC中,然后我们可以对它们进行post过滤。
代码类似于以下代码:
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中MDC.get(密钥)的值。如果您想要一个更复杂的过滤器,您可以自己扩展它,并自己查看MDC中的值。
发布于 2011-09-15 06:13:53
Matthew Farwell的答案(使用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
}
发布于 2011-09-13 23:35:15
我发现这个blog article非常有用。这可能会帮助您为您的用户创建日志条件。
https://stackoverflow.com/questions/7404435
复制相似问题