Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional logging with log4j

Tags:

The web application on which I am working occasionally develops data integrity issues for some of the users. I'd like to turn on trace level logging, but since we are dealing with 100s of requests per second trace logging every single request is out of the question.

Is there a way with log4j to be able to log conditionally? In other words, I would like to be able to get trace logs only when specific users make a request. Since I don't know beforehand which users will be affected, I cannot simply temporarily hard-code usernames.

Edit:

I think I need to be a little clearer. I can easily add conditions to my log statements. For example

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"); } 

The difficulty is dynamically altering the condition that sets the log level. In other words, in the example above, how can I set the value of usernameFilter, other than hard-coding it.

like image 684
Dave Isaacs Avatar asked Sep 13 '11 15:09

Dave Isaacs


People also ask

What is a Log4j filter?

</RollingFile> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="RollingFile">

What is routing appender?

The routing appender evaluates a pattern which, thanks to log4j2 placeholding support, can be an environment variable with a default. Then the pattern allows to select the Route to use to actually log the log event. In other words, the router (or routing appender) behaves as a proxy in front of other appenders :).

What is additivity in Log4j?

Additivity is set to true by default, that is children inherit the appenders of their ancestors by default. If this variable is set to false then the appenders found in the ancestors of this logger are not used.


1 Answers

You want to look at Nested Diagnostic Contexts or Mapped Diagnostic Contexts in log4j or slf4j. An NDC/MDC allows you to insert data into your session that can be filtered by log4j.

So you would define the user name to be in the NDC and then you can change the log4j.properties to change the logging level for specific users.

An MDC uses a Map, whereas an NDC is based upon a stack principle. If you're using slf4j, you can even create separate log files depending upon the information in your MDC.

For instance, we did this when users logged into a website. We wanted to trace what a particular user was doing (retrospectively), so we added the user name and session id to the NDC, and then we could post filter on those.

The code was similar to the following:

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);     } } 

In your log4j.xml, this filters based upon the user:

  <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} outputs the value of MDC.get(key) in an MDC. If you wanted a more complex filter, you can extend it yourself, and look at the values in the MDC yourself.

like image 196
Matthew Farwell Avatar answered Oct 22 '22 02:10

Matthew Farwell