wake-up-neo.net

So erstellen Sie einen benutzerdefinierten Appender in log4j2

Wie in diesem Link diskutiert: Wie erstelle ich einen eigenen Appender in log4j?

Um einen benutzerdefinierten Appender in log4j 1.x zu erstellen, müssen wir die AppenderSkeleton-Klasse erweitern und ihre Append-Methode implementieren.

In ähnlicher Weise wie wir einen benutzerdefinierten Appender in log4j2 erstellen können, da die AppenderSkelton-Klasse nicht erweitert werden muss und alle anderen Appender die AppenderBase-Klasse erweitern.

40
saurabh goyal

Dies funktioniert in log4j2 ganz anders als in log4j-1.2.

In log4j2 erstellen Sie hierfür ein Plugin. Das Handbuch enthält eine Erläuterung mit einem Beispiel für einen benutzerdefinierten Appender hier: http://logging.Apache.org/log4j/2.x/manual/extending.html#Appenders

Es kann zweckmäßig sein, org.Apache.logging.log4j.core.appender.AbstractAppender zu erweitern, dies ist jedoch nicht erforderlich.

Wenn Sie Ihre benutzerdefinierte Appender-Klasse mit @Plugin(name="MyCustomAppender", .... kommentieren, wird der Name des Plugins zum Namen des Konfigurationselements. Eine Konfiguration mit Ihrem benutzerdefinierten Appender würde dann folgendermaßen aussehen:

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

Beachten Sie, dass das packages-Attribut in der Konfiguration eine durch Kommas getrennte Liste aller Pakete mit benutzerdefinierten log4j2-Plug-Ins ist. Log4j2 durchsucht diese Pakete im Klassenpfad nach mit @Plugin annotierten Klassen.

Hier ein Beispiel für einen benutzerdefinierten Appender, der auf der Konsole gedruckt wird:

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);
    }
}

Weitere Informationen zu Plugins finden Sie unter: http://logging.Apache.org/log4j/2.x/manual/plugins.html

Wenn das Handbuch nicht ausreicht, kann es sinnvoll sein, den Quellcode der integrierten Appender in log4j-core zu betrachten.

71
Remko Popma

Es sieht so aus, als würden Plugin-Appender beim Start gescannt und können nicht zur Laufzeit hinzugefügt werden. Ist das wahr?

wenn Sie während der Ausführung einen neuen Appender hinzufügen möchten, können Sie mit der Eigenschaft "monitorInterval" die Protokollkonfiguration aktualisieren, d. h.

    <Configuration monitorInterval="60">
1
Javoslaw

Für die Benutzer, die in TextArea ausgeben müssen, ist hier ein funktionierender Tweak

TextArea statisch machen

NetBeans Swing TextArea ist nicht statisch, verursacht Probleme

Fügen Sie Ihrem Frame eine statische Methode hinzu

public class MyFrame extends javax.swing.JFrame {
    ...
    public static void outputToTextArea(String message) {
        jTextArea.append(message);
    }

Appender-Append aufrufen

@Override
public void append(LogEvent event) {
    final byte[] bytes = getLayout().toByteArray(event);
    MyFrame.outputToTextArea(new String(bytes));
}
0
pppk520

Wie Sie bereits bemerkt haben, ist AppenderSkeleton nicht mehr verfügbar, daher funktionieren die Lösungen in Wie erstelle ich meinen eigenen Appender in log4j? nicht.

Die Verwendung von Mockito oder einer ähnlichen Bibliothek zum Erstellen eines Appenders mit einem ArgumentCaptor funktioniert nicht, wenn Sie mehrere Protokollmeldungen erwarten, da das MutableLogEvent über mehrere Protokollmeldungen wiederverwendet wird.

Die allgemeinste Lösung, die ich für log4j2 gefunden habe, besteht darin, eine Scheinimplementierung bereitzustellen, die alle Nachrichten aufzeichnet. Es werden keine zusätzlichen Bibliotheken wie Mockito oder JMockit benötigt.

private static MockedAppender mockedAppender;
private static Logger logger;

@Before
public void setup() {
    mockedAppender.message.clear();
}

/**
 * For some reason mvn test will not work if this is @Before, but in Eclipse it works! As a
 * result, we use @BeforeClass.
 */
@BeforeClass
public static void setupClass() {
    mockedAppender = new MockedAppender();
    logger = (Logger)LogManager.getLogger(ClassWithLoggingToTest.class);
    logger.addAppender(mockedAppender);
    logger.setLevel(Level.INFO);
}

@AfterClass
public static void teardown() {
    logger.removeAppender(mockedAppender);
}

@Test
public void test() {
    // do something that causes logs
    for (String e : mockedAppender.message) {
        // add asserts for the log messages
    }
}

private static class MockedAppender extends AbstractAppender {

    List<String> message = new ArrayList<>();

    protected MockedAppender() {
        super("MockedAppender", null, null);
    }

    @Override
    public void append(LogEvent event) {
        message.add(event.getMessage().getFormattedMessage());
    }
}
0
joseph