Wie erstelle ich einen benutzerdefinierten Appender in log4j2?

Lesezeit: 5 Minuten

Wie erstelle ich einen benutzerdefinierten Appender in log4j2
saurabh goyal

Wie in diesem Link beschrieben: 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.

Ebenso können wir einen benutzerdefinierten Appender in log4j2 erstellen, da wir keine AppenderSkelton-Klasse zum Erweitern haben und alle anderen Appender die AppenderBase-Klasse erweitern.

Wie erstelle ich einen benutzerdefinierten Appender in log4j2
Remko Popma

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

In log4j2 würden Sie dafür ein Plugin erstellen. Das Handbuch enthält eine Erklärung mit einem Beispiel für einen benutzerdefinierten Appender hier: http://logging.apache.org/log4j/2.x/manual/extending.html#Appenders

Es kann bequem sein, zu verlängern org.apache.logging.log4j.core.appender.AbstractAppender, dies ist jedoch nicht erforderlich.

Wenn Sie Ihre benutzerdefinierte Appender-Klasse mit Anmerkungen versehen @Plugin(name="MyCustomAppender", ...., wird der Plugin-Name zum Namen des Konfigurationselements, sodass eine Konfiguration mit Ihrem benutzerdefinierten Appender dann so aussehen würde:

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

Notiere dass der packages -Attribut in der Konfiguration ist eine durch Kommas getrennte Liste aller Pakete mit benutzerdefinierten log4j2-Plugins. Log4j2 durchsucht diese Pakete im Klassenpfad nach Klassen, die mit @Plugin annotiert sind.

Hier ist 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 Details zu Plugins:
http://logging.apache.org/log4j/2.x/manual/plugins.html

Wenn das Handbuch nicht ausreicht, kann es hilfreich sein, sich den Quellcode für die eingebauten Appender in log4j-core anzusehen.

  • Es sieht so aus, als würden Plugin-Appender beim Start gescannt und kann nicht während der Laufzeit hinzugefügt werden. Ist das wahr? Wenn dies der Fall ist, beantwortet dies nicht die Frage, wie das Verhalten von Log4J 2 programmgesteuert geändert werden kann.

    – hier

    17. Oktober 14 um 21:11 Uhr

  • @ingyhere Das programmgesteuerte Konfigurieren von Log4j2 ist in der Tat eine separate Frage. Diese log4j2-Handbuchseite kann ein guter Ausgangspunkt sein, um mehr zu erfahren: loggen.apache.org/log4j/2.x/manual/… Andernfalls möchten Sie vielleicht eine neue Frage stellen.

    – Remko Popma

    18. Oktober 14 um 7:28 Uhr


  • Das PatternLayout von Log4j2 ist Thread-sicher und erfordert keine Sperrung. Ja, die Verwendung der Sperre macht den Appender synchron. Wenn Ihr Appender die resultierenden Bytes an ein threadsicheres Ziel schreibt, muss Ihr Appender keine Sperren durchführen.

    – Remko Popma

    7. Juni 17 um 23:37 Uhr

  • @Aman Mehrere Threads dürfen dieselbe Lesesperre erwerben. Da nichts jemals die zugehörige Schreibsperre erwirbt, werden diese lock / unlock Anrufe bringen nichts. Dieser Code ist nicht Thread-sicher, und mehrere Threads können den geschützten Code gleichzeitig ausführen.

    – Daniel Yankowsky

    8. Juni 17 um 19:52 Uhr


  • @SewerynHabdank-Wojewódzki Es kann besser sein, auf der Mailingliste der Log4j-Benutzer nachzufragen oder ein JIRA-Ticket zu erstellen, wenn der dreimal erstellte Appender wie ein Fehler aussieht.

    – Remko Popma

    5. Juli 18 um 6:50 Uhr

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

Um während der Ausführung einen neuen Appender hinzuzufügen, können Sie die Eigenschaft monitorInterval verwenden, um die Protokollkonfiguration zu aktualisieren, dh alle 60 Sekunden:

    <Configuration monitorInterval="60">

  • Sie können einen Appender programmgesteuert hinzufügen, aber wenn monitorInterval festgelegt ist, geht der hinzugefügte Appender verloren, wenn Änderungen an der Konfigurationsdatei vorgenommen werden.

    – rgoers

    14. Oktober 16 um 3:49 Uhr

Wie erstelle ich einen benutzerdefinierten Appender in log4j2
Joseph

Wie Sie darauf hingewiesen haben, ist AppenderSkeleton nicht mehr verfügbar, also die Lösungen in How to create my own Appender in log4j? wird nicht funktionieren.

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 für mehrere Protokollmeldungen wiederverwendet wird.

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

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.AbstractAppender;    

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

.

734500cookie-checkWie erstelle ich einen benutzerdefinierten Appender in log4j2?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy