我工作的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");
}
Run Code Online (Sandbox Code Playgroud)
困难在于动态地改变设置日志级别的条件.换句话说,在上面的示例中,我如何设置usernameFilter的值,而不是硬编码.
Mat*_*ell 20
您想在log4j或slf4j中查看嵌套诊断上下文或映射诊断上下文.NDC/MDC允许您将数据插入到可由log4j过滤的会话中.
因此,您要将用户名定义为NDC,然后您可以更改log4j.properties以更改特定用户的日志记录级别.
MDC使用Map,而NDC基于堆栈原则.如果您正在使用slf4j,您甚至可以根据MDC中的信息创建单独的日志文件.
例如,我们在用户登录网站时执行此操作.我们想跟踪特定用户正在做什么(回顾性地),因此我们将用户名和会话ID添加到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);
}
}
Run Code Online (Sandbox Code Playgroud)
在您的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>
Run Code Online (Sandbox Code Playgroud)
%X {key}在MDC中输出MDC.get(key)的值.如果您想要一个更复杂的过滤器,您可以自己扩展它,并自己查看MDC中的值.
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();
}
}
Run Code Online (Sandbox Code Playgroud)
使用以下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>
Run Code Online (Sandbox Code Playgroud)
然后,在任何你想要标记过滤的地方,输入如下代码:
MDC.put("HEALTHCHECK", "true");
try
{
// do healthcheck stuff that generates unnecessary logs
}
finally
{
MDC.remove("HEALTHCHECK"); // not sure this is strictly necessary
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
29892 次 |
| 最近记录: |