Test log4j2 with JUnit using a custom appender

In previous articles, I’ve described how to test System.out with JUnit and how to test log4j with JUnit. This article describes how to test log4j2 logging with JUnit. This largely follows the same technique as testing log4j logging but using the the newer log4j2 APIs.

Differences between log4j and log4j2

log4j2 follows a similar design to log4j but has the following differences:

  • Package structure: The root package name has changed fromĀ  org.apache.log4j to org.apache.logging.log4j. The core implementation classes (Logger, Appender ,Layout etc.) are in org.apache.log4j.logging.core.
  • Layout and Appender instances are created with Builder classes instead of constructors.
  • The WriterAppender class that we use to capture log output appends to a Writer instead of an OutputStream.
  • Configuration has changed. The old log4j.properties / log4j.xml config file is replaced with log4j2 equivalents and JSON and YAML formats are now supported.

JUnit @Rule

The JUnit ExternalResource described in the previous article now looks like this:

Note in particular the difference in the way that the Layout and Appender are constructed.

This JUnit ExternalResource rule can be used in a test in exactly the same way as before:

Example

I used this technique when upgrading the VoiceXMLRiot project from log4j to log4j2. Check the code in GitHub for examples:

 

4 Comments

  • Rajan
    June 9, 2020 - 1:45 pm | Permalink

    Thank you! I tried these classes but outContent (return outContent.toString();) is always empty. Am i missing anything?

    • Rajan
      June 9, 2020 - 5:13 pm | Permalink

      never mind, wrong log level.

  • Evgenii
    July 15, 2020 - 12:40 pm | Permalink

    the same as mentioned, in all log levels result is empty string “”.

  • Matt
    July 26, 2020 - 2:13 am | Permalink

    Thank you so much Stuart! It worked for my project. However to make it works like a charm I have to make some small changes to the customised Appender class. Here are my changes:

    – Set the PATTERN to this: “%-5level %m%n”

    – Added one extra method to the class Appender to get appropriate log messages, eg: error, debug, infor or warning. Here is the implementation:

    public List getLogMessageListByLevel(Level level) {

    String[] logMessages = charArrayWriter.toString().split("\\n");

    if (level == Level.ALL) {
    return Arrays.asList(logMessages);
    }

    List returnedList = new ArrayList();
    for (String msg: logMessages) {
    if (msg.contains(level.name())) {
    returnedList.add(msg);
    }
    }
    return returnedList;
    }

  • Leave a Reply

    Your email address will not be published. Required fields are marked *