How to Create My Own Appender in Log4J

How to create my own Appender in log4j?

Update: the provided solution is valid for Log4J 1.x . If you're looking for 2.x versions, take a look at this article: How to create a custom appender in log4j2

You should extend AppenderSkeleton class, that (quoting javadoc) "provides the code for common functionality, such as support for threshold filtering and support for general filters."

If you read the code of AppenderSkeleton, you'll see that it handles almost all, leaving to you just:

  1. protected void append(LoggingEvent event)
  2. public void close()
  3. public boolean requiresLayout()

The core method is append. Remember that you don't need to implement the filtering logic in it because it is already implemented in doAppend that in turn calls append.
Here I made a (quite useless) class that stores the log entries in an ArrayList, just as a demo.

public /*static*/ class MyAppender extends AppenderSkeleton {
ArrayList<LoggingEvent> eventsList = new ArrayList();

@Override
protected void append(LoggingEvent event) {
eventsList.add(event);
}

public void close() {
}

public boolean requiresLayout() {
return false;
}

}

Ok, let's test it:

public static void main (String [] args) {

Logger l = Logger.getLogger("test");

MyAppender app = new MyAppender();

l.addAppender(app);

l.warn("first");
l.warn("second");
l.warn("third");

l.trace("fourth shouldn't be printed");

for (LoggingEvent le: app.eventsList) {
System.out.println("***" + le.getMessage());
}
}

You should have "first", "second", "third" printed; the fourth message shouldn't be printed since the log level of root logger is debug while the event level is trace. This proves that AbstractSkeleton implements "level management" correctly for us. So that's definitely seems the way to go... now the question: why do you need a custom appender while there are many built in that log to almost any destination? (btw a good place to start with log4j: http://logging.apache.org/log4j/1.2/manual.html)

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.

how to create a log4j custom appender and control the filename

I think you can achieve first 2 with

using RollingFileAppender and specifying FixedWindowRollingPolicy for RollingPolicy

as for the #3 you can always write your own handler

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.

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



Related Topics



Leave a reply



Submit