Controlling Log4j Logs with Contexts and Filters

Its a problem we’ve all had. Something has gone awry, you jack up the log level to debug and all of the sudden you are inundated with everything under the sun. While one option could be changing some of the logs to trace level there is another option, using Log4j contexts. Log4j contains two different contexts mapped and nested. In this post I’ll focus on nested.

The first thing to do is to isolate the section of your code that you want to create a context for. Once you have accomplished this you make a static call to NDC.push(). The parameter passed in is the string name for the context you would like create. I recommend pulling these strings out into a constants file ease of use and additionally calling .intern() on them so you can use pointer equality checks later when we code up the filters. When you leave the context you call NDC.pop() and life goes back to normal. Finally, remember to call NDC.remove() when you leave the thread.
The code ends up looking like this:

NDC.push(Constants.HEARTBEAT_CONTEXT);
try{
  if (log.isDebugEnabled()) {
    log.debug("[MASTER/SLAVE] Publishing heartbeat");
  }
  doStuff();
}
finally {
  NDC.pop();
  NDC.remove();
}

Now that we have the logs tagged with the correct context we need to create a log4j filter by extending the filter class and overriding the decide(LoggingEvent event) method. The important concept to remember here is that filters can be chained which means your decision results in either a DENY, ACCEPT, or NEUTRAL decision where deny forces the log to be rejected, accept force the log to be written and neutral passes the decision down the chain. Additionally, you access the context by calling getNDC() on the LoggingEvent object passed in to the decide method.
The code then looks like this:
public class HeartbeatFilter extends Filter
{
  @Override
  public int decide(final LoggingEvent event) {
    if (event.getNDC() == Constants.HEARTBEAT_CONTEXT) {
      return DENY;
    }
    return NEUTRAL;
  }
}

Finally we have to add this filter to our log4j configuration. For this we have to make sure we are using the xml configuration file type as it is more expressive and allows us to define filters to use where as the property configuration file type does not. All we have to do is add a filter tag to an appender in the xml and point it at our class.
It looks something like this:

<appender name="console" class="org.apache.log4j.ConsoleAppender">
  <param name="Target" value="System.out"/>
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
  </layout>
  <filter class="my.package.HeartbeatFilter" />
</appender>
About these ads

About Benjamin Darfler
Coder, Meditator, Photographer

5 Responses to Controlling Log4j Logs with Contexts and Filters

  1. Caligula says:

    That sure seems like an awful lot of code noise just to provide contextual logging. I think I’d just rather use grep and use a known log string prefix.

  2. @Caligula that would certainly work for basic filtering and this example is fairly basic. However, the context scale up considerably having nested contexts or mapped contexts with multiple values. Moreover, since these contexts are thread specific you can do things like separate processing of requests from multiple clients for example.

  3. kasper graversen says:

    I have made a commit-rollback functionality for Log4J.. I just never got to release it. it’s called lacunalog. It seems to be less burdenous than the exmaples shown here.

    kasper / http://www.firstclassthoughts.co.uk

  4. me says:

    I think that the NDC is a great way to seperate Logging. Especially try to log in an applicationserver like JBoss. To differentiate between several applications there are only some ways and the best I’ve met is the one using a context (for webapps it’s fairly easy to configure.)
    Great article.

  5. @Kasper sounds interesting, but what is the point if you never released anything?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: