Logging in Eclipse Plugins with JUnit Support

Logging can be used for a lot of different of use cases, ranging from debug messages during development upto application monitoring in production.

In the past, log4j was set as a de facto standard, slf4j and the java internal java.util.logging have been developed.
So which should one use? It depends…
While java.util.logging is build into the sdk and one can use it without setting up a logging environment, it provides only limitted flexibility compared to log4j and slfj.
There is a good blog post about which logging to be used also providing a small decision tree on page 2 about how to decide between java.util.logging and log4j: http://java.sys-con.com/node/48541. In this article Joe McNamara discusses logging in general.

But what about the development of eclipse plugins? Especially if you have code, which is executed by JUnit tests – not JUnit Plugin tests! – and by running eclipse plugin instances? In this article I describe how to setup your infrastructure to use a flexible log4j and to get logging output also during your junit test runs.

Why to use not only JUnit Plugin tests? It’s a simple matter of development performance. A plugin development test needs to startup an eclipse instance which takes a lot of time and one will tend to run his tests less often because they need to much time. Same applies to your continous integration builds.

First of all, you should install log4j in your eclipse. It is provided encapsulated as a plugin by the eclipse orbit project:
You can just use your Help->Install new software and add the latest orbit update site such as http://download.eclipse.org/tools/orbit/downloads/drops/R20120526062928/repository/

Afterwards, add a dependency to the org.apache.log4j plugin in your own plugin.xml.

Now you can use log4j loggers in your classes usual:
import org.apache.log4j.Logger;
...
public class MyClass {
private Logger logger = Logger.getLogger(MyClass .class);
...
public void method(){
logger.debug("ping");
}
}

But now, when you run this code within a unit test your woll endup with a message as this one:
log4j:WARN No appenders could be found for logger (org.splevo.diffing.MatchEngineDiffingService).
log4j:WARN Please initialize the log4j system properly.

So how to prevent it?
The simple answer is, you need to initialize a logging environment.
For your production environment, you normally setup a logging environment configured with a properties or xml file, or event configurable during runtime. But you might not want to have such a complexity for simple logging output in your test environment. Remember, your unit tests should run as fast as possible without any big configuration file loading overhead etc.
So what you can do is, to make use of the log4j BasicConfigurator which is able to initialize a default logging environment for your: .
The best way, to do this is within the setup method of your testcase instance. For example using the code below (JUnit 4):

/**
* Prepare the test.
* Initializes a log4j logging environment.
*/
@Before
public void setUp() {
// set up a basic logging configuration for the test environment
BasicConfigurator.resetConfiguration();
BasicConfigurator.configure();
}

Note: You should call resetConfiguration() first. Otherwise a new Appender will be registered for each unit test which is executed and you will end up with all log messages presented multiple times (once per appender/test case startup).

If you want to use a more reduced logging output, you could for example provide a ConsoleAppender with a SimpleLayout to the BasicConfigurator:
/**
* Prepare the test.
* Initializes a log4j logging environment.
*/
@Before
public void setUp() {
// set up a basic logging configuration for the test environment
BasicConfigurator.resetConfiguration();
BasicConfigurator.configure(new ConsoleAppender(new SimpleLayout()));
}

Or if you want to have a really minimal logging output similar as if you would just call System.out.println() in your code, you can use a PatternLayout with a %m%n configuration for just the message and a line break:
/**
* Prepare the test.
* Initializes a log4j logging environment.
*/
@Before
public void setUp() {
// set up a basic logging configuration for the test environment
BasicConfigurator.resetConfiguration();
BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%m%n")));
}

Leave a Comment