Custom Layout in Log4J2

Logging is probably one of the last things that a developer focusses on and yet is probably the most critical tool in the armory of developers and operation engineers in troubleshooting and more importantly understanding their applications as they run in Production.

In this post, I am going to talk about how you can write a custom layout using Log4J2 which is version 2 of one of the 2 popular frameworks for logging information from a Java application.

For starters I want to provide a disclaimer that writing a custom layout is not something that you do on a regular basis since the options available in Log4J2 both with respect to layouts and appenders covers all possible use cases. However there might be occasions when you may want to write a custom layout, in my case it was to force an opinionated log line across all applications as a part of a centralized logging strategy across our set of micro services.

In order to write a custom layout, you first have to include the following Maven dependency

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>2.6.2</version>
</dependency>

Write a Java class that extends a log4j2 class. Notice the annotation for @Plugin where you define the actual name of the element that will eventually go into the log4j2.xml file. In this example the value of the name attribute EventJsonLayout will appear as <EventJsonLayout/> in your log4j2.xml file. The re

/**
 * Custom JsonLayout to print out the audit log data
 */
@Plugin(name = "EventJsonLayout", category = "Core", elementType = "layout", printObject = true)
public final class EventJsonLayout extends AbstractStringLayout {
....
}

The above class then needs to have a static factory method annotated with @PluginFactory to tell Log4j2 to use this to initialize the layout. All attributes that you want to make available to clients to modify through their log4j2.xml should be annotated with @PluginAttribute

@PluginFactory
    public static EventJsonLayout createLayout(@PluginAttribute(value = "charset", defaultString = "UTF-8") Charset charset) {
        return new EventJsonLayout(charset);
    }

Finally the key method that needs to be implemented is the toSerializable method which is responsible for taking the actual log event which log4j2 will pass via the LogEvent argument and convert it into a String that the framework can use while sending the output

/**
     * Write data to the output stream
     *
     * @param event
     * @return
*/
public String toSerializable(LogEvent event) {
        ....
}

Lastly and most importantly, the above in itself does not tell Log4J2 to respect this layout. You need to generate the plugin listing files for your custom layout. W/o the final step elaborated below, you will get a compile time error if you reference this layout in your log4j2.xml file. To glue all of this you need to use. By default you don’t have to do anything since the log4j annotation processor is picked up by the Java compiler but in case it has been disabled then the following maven plugin will make that happen

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${compiler.plugin.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <debug>${debug.state}</debug>
                </configuration>
                <executions>
                    <execution>
                        <id>log4j-plugin-processor</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <phase>process-classes</phase>
                        <configuration>
                            <proc>only</proc>
                            <annotationProcessors>
                                <annotationProcessor>
                                    org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor
                                </annotationProcessor>
                            </annotationProcessors>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

For more information on plugin listing files go to Log4J2 Plugin Listing Files

For more information on writing custom layouts go to Log4J2 Custom Layouts

One thought on “Custom Layout in Log4J2”

Leave a Reply

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