使用log4j进行条件记录

我正在使用的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的值,而不是硬编码。

您想在log4j或slf4j中查看嵌套诊断上下文或映射诊断上下文 。 NDC / MDC允许您将数据插入到可由log4j过滤的会话中。

因此,您将定义要在NDC中的用户名,然后您可以更改log4j.properties以更改特定用户的日志记录级别。

MDC使用Map,而NDC基于堆栈原则。 如果您使用的是slf4j ,您甚至可以根据MDC中的信息创建单独的日志文件。

例如,我们在用户登录网站时执行此操作。 我们想跟踪特定用户正在做什么(追溯),因此我们将用户名和会话ID添加到NDC,然后我们可以对这些用户名和会话ID进行过滤。

代码类似于以下内容:

 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中,此filter基于用户:

                

%X {key}在MDC中输出MDC.get(key)的值。 如果您想要一个更复杂的filter,您可以自己扩展它,并自己查看MDC中的值。

Matthew Farwell的回答(使用MDC)是对我有用的,他提到编写自己的filter。 我需要在某些情况下隐藏日志记录消息。 具体来说,我们的健康检查呼叫比典型的用户使用频率更高,并且不必要地填充日志。 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片段激活filter(“HEALTHCHECK”是键,“true”是我要过滤的值):

       

然后,在您想要标记过滤的任何地方,输入如下代码:

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

我发现这篇博客文章非常有帮助。 这可以帮助您创建为用户记录的条件。

我做了一个解决方法如下

在log4j.xml中配置日志目标,如下所示:

               

创建一个附加目标标签的客户记录器方法[ trackfile ]

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

使用上述方法记录您的信息:

 logfile("your log message") 

在此处输入图像描述