How to Create a Custom Appender in Log4J2

How to Create a Custom Appender in log4j2?

This works quite differently in log4j2 than in log4j-1.2.

In log4j2, you would create a plugin for this. The manual has an explanation with an example for a custom appender here: http://logging.apache.org/log4j/2.x/manual/extending.html#Appenders

It may be convenient to extend org.apache.logging.log4j.core.appender.AbstractAppender, but this is not required.

When you annotate your custom Appender class with @Plugin(name="MyCustomAppender", ...., the plugin name becomes the configuration element name, so a configuration with your custom appender would then look like this:

<Configuration packages="com.yourcompany.yourcustomappenderpackage">
<Appenders>
<MyCustomAppender name="ABC" otherAttribute="...">
...
</Appenders>
<Loggers><Root><AppenderRef ref="ABC" /></Root></Loggers>
</Configuration>

Note that the packages attribute on the configuration is a comma-separated list of all the packages with custom log4j2 plugins. Log4j2 will search these packages in the classpath for classes annotated with @Plugin.

Here is a sample custom appender that prints to the console:

package com.yourcompany.yourcustomappenderpackage;

import java.io.Serializable;
import java.util.concurrent.locks.*;
import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.config.plugins.*;
import org.apache.logging.log4j.core.layout.PatternLayout;

// note: class name need not match the @Plugin name.
@Plugin(name="MyCustomAppender", category="Core", elementType="appender", printObject=true)
public final class MyCustomAppenderImpl extends AbstractAppender {

private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();

protected MyCustomAppenderImpl(String name, Filter filter,
Layout<? extends Serializable> layout, final boolean ignoreExceptions) {
super(name, filter, layout, ignoreExceptions);
}

// The append method is where the appender does the work.
// Given a log event, you are free to do with it what you want.
// This example demonstrates:
// 1. Concurrency: this method may be called by multiple threads concurrently
// 2. How to use layouts
// 3. Error handling
@Override
public void append(LogEvent event) {
readLock.lock();
try {
final byte[] bytes = getLayout().toByteArray(event);
System.out.write(bytes);
} catch (Exception ex) {
if (!ignoreExceptions()) {
throw new AppenderLoggingException(ex);
}
} finally {
readLock.unlock();
}
}

// Your custom appender needs to declare a factory method
// annotated with `@PluginFactory`. Log4j will parse the configuration
// and call this factory method to construct an appender instance with
// the configured attributes.
@PluginFactory
public static MyCustomAppenderImpl createAppender(
@PluginAttribute("name") String name,
@PluginElement("Layout") Layout<? extends Serializable> layout,
@PluginElement("Filter") final Filter filter,
@PluginAttribute("otherAttribute") String otherAttribute) {
if (name == null) {
LOGGER.error("No name provided for MyCustomAppenderImpl");
return null;
}
if (layout == null) {
layout = PatternLayout.createDefaultLayout();
}
return new MyCustomAppenderImpl(name, filter, layout, true);
}
}

For more details on plugins:
http://logging.apache.org/log4j/2.x/manual/plugins.html

If the manual is not enough, it may be useful to look at the source code for the built-in appenders in log4j-core.

create a custom log4j2 rolling file appender

The RollingFileAppender in Log4j 2.x is final, so you can not extend it. However you can obtain the functionality of your custom Log4j 1.x appender using:

  • A RoutingAppender, which can create appenders on demand,
  • Multiple RollingFileAppender that will write and rotate your files,
  • The EventLookup to retrieve the current thread name.

For a simple logfile-per-thread appender you can use:

<Routing name="Routing">
<Routes pattern="$${event:ThreadName}">
<Route>
<RollingFile name="Rolling-${event:ThreadName}"
fileName="logs/thread-${event:ThreadName}.log"
filePattern="logs/thread-${event:ThreadName}.log.%d{yyyy-MM-dd}">
<PatternLayout pattern="%d [%-5p] [%t] [%c{1}] [%M] - %m%n" />
<TimeBasedTriggeringPolicy />
</RollingFile>
</Route>
</Routes>
</Routing>

For a more complex configuration both the <Routing> appender and the <Routes> can contain a <Script> (cf. documentation):

  • the script in the <Routing> appender can initialize the staticVariables map and return a default route,
  • the script in the <Routes> component chooses the appropriate route based on staticVariables and the logging event.

How to setup a log4j2 custom appender with Spring Boot?

You have to add the package of your appender class in log4j.properties e.g.
packages = org.home.appenders

What is the preferred method for creating a custom appender in log4j2?

You need to put the package name (or names in a comma-separated list if multiple) in the packages attribute of the Configuration element of your log4j2.xml.

E.g.

<Configuration status="trace" packages="com.mycomp.myproject.appenders">
...

See the Log4j2 Configuration Documentation for more information.



Related Topics



Leave a reply



Submit