ushmajit sikdar
ushmajit sikdar

Reputation: 21

Migrating from Log4j 1.x to Log4j 2.x

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

Answers (3)

Pluto_rider
Pluto_rider

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

abramova-eg
abramova-eg

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

Remko Popma
Remko Popma

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

Related Questions