a peek into my MIND

December 7, 2009

Unit testing Log4j log statements.

Filed under: Java, Testing — Tags: , , — Bharat Kondeti @ 6:15 pm

Logging is an important aspect in writing any software application. Logs properly utilized provide valuable information related to code flow. Mining logs is a way to gather data related to performance of the application and to debug the application.

As part of our current application we wrote tools in Perl and Groovy to mine the logs to collect statistics related to the application. In these tools, we primarily look for string patterns and if some one unintentionally changes the log statements inside the code it breaks our tools also. It’s always beneficial to surround SOME of the log statements with Junit test.

Extending AppenderSkeleton to create a custom append-er.

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;

public class TestingAppender extends AppenderSkeleton {

  //We are collecting all the log messages in to a list
  private static List messages = new ArrayList();

  // This method is called when ever any logging happens
  // We are simply taking the log message and adding to our list
  @Override
  protected void append(LoggingEvent event) {
    messages.add(event.getRenderedMessage());
  }

  //This method is called when the appender is closed.
  //Gives an opportunity to clean up resources
  public void close() {
    messages.clear();
  }

  public boolean requiresLayout() {
    return false;
  }

  public static String[] getMessages() {
    return (String[]) messages.toArray(new String[messages.size()]);
  }

  public static void clear() {
    messages.clear();
  }
}

Then we need to write couple of methods to setup the custom append-er and remove it. As part of setUp and tearDown methods of JUnit tests appropriate methods can be called.


private void setupLog4j(TestingAppender appender) {
  //Get the root logger for the
  Logger root = Logger.getRootLogger();

  //If there are no appenders, means Log4j is not initialized properly
  if (!root.getAllAppenders().hasMoreElements()) {
    System.out.println("*******Log4j is not initilized**********");
  } else {

   //Set to appropriate log level and add custom appender
    root.setLevel(Level.ERROR);
    root.addAppender(appender);
  }
}

private void resetLog4j(TestingAppender appender) {
  TestingAppender.clear();
  Logger root = Logger.getRootLogger();
  root.setLevel(Level.FATAL);
  root.removeAppender(appender);
}

As part of tests we can call TestingAppender.getMessages() to get the list of messages and assert for the appropriate log message. This way we can have unit tests for log statements also.

Advertisements

1 Comment »

  1. Thanks for posting this, good stuff. I’m now using this technique to verify particular code paths in unit tests.

    Comment by Ben Hardy (@benhardy) — February 6, 2012 @ 11:23 pm


RSS feed for comments on this post.

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

Blog at WordPress.com.

%d bloggers like this: