Reputation: 21
I am trying to convert a class which was earlier written using AppenderSkeleton in log4j 1.x now I am trying to migrate my service to log4j 2.6.
The code:
package com.amazon.digital.music.purchasing.scheduler.test;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
/**
* A log appender which collects the log messages.
* Automatically appends itself to the root logger.
*
*/
class LogMessagesCollector extends AppenderSkeleton {
private final List<String> messages = new ArrayList<String>();
public LogMessagesCollector() {
final Logger logger = Logger.getRootLogger();
logger.addAppender(this);
}
@Override
public boolean requiresLayout() {
return false;
}
@Override
protected void append(final LoggingEvent loggingEvent) {
messages.add(loggingEvent.getMessage().toString());
}
@Override
public void close() {
final Logger logger = Logger.getRootLogger();
logger.removeAppender(this);
}
public List<String> getMessages() {
return messages;
}
I followed the link: How to Create a Custom Appender in log4j2? to understand how custom appenders are written in log4j2 but not being able to code a class which would replace this one.
Any help would be great.Thanks in advance!
Upvotes: 2
Views: 3168
Reputation: 137
Here is the one thing you can do
import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Plugin(name = "LogMessagesCollector", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
public class LogMessagesCollector extends AbstractAppender {
private static List<String> messages = new ArrayList<String>();
private static volatile CustomAppender instance;
public LogMessagesCollector(final String name, final Filter filter, final Layout<? extends Serializable> layout, final boolean ignoreExceptions, final Property[] properties) {
super(name, filter, layout, ignoreExceptions, properties);
}
@PluginFactory
public static LogMessagesCollector createAppender(@PluginAttribute("name") String name,
@PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
@PluginElement("Layout") Layout layout,
@PluginElement("Filters") Filter filter,
@PluginElement("properties") Property[] properties) {
if (layout == null) {
layout = PatternLayout.createDefaultLayout();
}
instance = new LogMessagesCollector(name, filter, layout, ignoreExceptions, properties);
return instance;
}
public static LogMessagesCollector getInstance() {
return instance;
}
@Override
public void append(LogEvent event) {
messages.add(event.getMessage().getFormattedMessage());
}
public static List<String> getMessages() {
return messages;
}
public static void clear() {
messages.clear();
}
}
And configuration for the above class can be log4j2.xml place it inside resource folder..
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE" packages="com.example.demo">
<Appenders>
<LogMessagesCollector name="CustomAppender" >
<PatternLayout pattern="=== %d [%.4t] %-5p %c{1} - %m%n" />
</LogMessagesCollector>
</Appenders>
<Logger name="com.example.demo" level="INFO">
<appender-ref ref="CustomAppender" level="INFO"/>
</Logger>
</Configuration>
Upvotes: 1
Reputation: 21
Come across the same issue. Here is the template for custom solution
log4j2.properties
name = PropertiesConfig
property.filename = logs
appenders = basic
appender.basic.type = Basic
appender.basic.name = Basic
appender.basic.layout.type= PatternLayout
appender.basic.layout.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
rootLogger.level = debug
rootLogger.appenderRefs = flume
rootLogger.appenderRef.flume.ref = Basic
BasicAppender.java
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
import java.io.Serializable;
@Plugin(name = "Basic", category = "Core", elementType = "appender", printObject = true)
public class BasicAppender extends AbstractAppender {
private static volatile BasicAppender instance;
public BasicAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout){
super(name, filter, layout);
}
@PluginFactory
public static BasicAppender createAppender(@PluginAttribute("name") String name,
@PluginElement("Layout") Layout layout,
@PluginElement("Filters") Filter filter){
if (layout == null){
layout = PatternLayout.createDefaultLayout();
}
return new BasicAppender(name, filter, layout);
}
public static BasicAppender getInstance(){
return instance;
}
@Override
public void append(final LogEvent event){
//custom actions
}
}
Upvotes: 1
Reputation: 36754
Please take a look at the ListAppender in the unit tests for the log4j-core module. It is similar in that it collects log events in a list. It has some other features to facilitate testing, but it can be a good template for a custom appender.
Upvotes: 2