it-swarm.com.de

Appender mit slf4j und log4j2 dynamisch hinzufügen

Ich möchte einen Appender dynamisch erstellen und zu einem Logger hinzufügen. Dies scheint jedoch mit slf4j nicht möglich zu sein. Ich kann meinen Appender zu einem Log4j-Logger hinzufügen, kann den Logger jedoch nicht mit dem Slf4j-LoggerFactoy abrufen.

Was ich tun möchte: Ich erstelle eine Testklasse (keinen jUnit-Test) und übergebe im Konstruktor einen Logger, damit die Testklasse verwendet werden kann. Jede Instanz der Testklasse benötigt einen eigenen Logger und einen eigenen Appender, der das Protokoll speichert, sodass es später in einem HTML-Bericht verwendet werden kann.

Was ich ausprobiert habe (zur Vereinfachung habe ich einen jUnit-Test erstellt):

  import static org.junit.Assert.assertEquals;

  import Java.util.LinkedList;
  import Java.util.List;

  import org.Apache.logging.log4j.core.LogEvent;
  import org.junit.Test;
  import org.slf4j.helpers.Log4jLoggerFactory;

  import ch.fides.fusion.logging.ListAppender;

  public class ListAppenderTest {

      @Test
      public void test() {

          String testName = "test1";

          // the log messages are to be inserted in this list
          List<LogEvent> testLog = new LinkedList<>();

          // create log4j logger
          org.Apache.logging.log4j.core.Logger log4jlogger = (org.Apache.logging.log4j.core.Logger) org.Apache.logging.log4j.LogManager
                                          .getLogger("Test:" + testName);

          // create appender and add it to the logger
          ListAppender listAppender = new ListAppender("Test:" + testName + ":MemoryAppender", testLog);
          log4jlogger.addAppender(listAppender);

          // get the slf4j logger
          org.slf4j.helpers.Log4jLoggerFactory loggerFactory = new Log4jLoggerFactory();
          org.slf4j.Logger testLogger = loggerFactory.getLogger("Test:" + testName);

          // test it
          final String TEST_MESSAGE = "test message";
          testLogger.info(TEST_MESSAGE);

          assertEquals(1, testLog.size());
          LogEvent logEvent = testLog.get(0);
          assertEquals(TEST_MESSAGE, logEvent.getMessage().getFormattedMessage() );
      }

  }

und das ist mein grundlegender Appender:

 package ch.fides.fusion.logging;

  import Java.util.List;

  import org.Apache.logging.log4j.core.LogEvent;
  import org.Apache.logging.log4j.core.appender.AbstractAppender;

  public class ListAppender extends AbstractAppender {

      private final List<LogEvent> log;

      public ListAppender(String name, List<LogEvent> testLog) {
          super(name, null, null);
          this.log = testLog;
      }

      @Override
      public void append(LogEvent logEvent) {
          log.add(new TestLogEvent(logEvent));
      }

  }

Was kann ich tun, damit das funktioniert? Vielleicht nähere ich mich dem falschen Standpunkt an, möchte aber vermeiden, eine eigene Logger-Klasse zu erstellen. Jede Hilfe wird sehr geschätzt.

13
Daniele Torino

Zugriff auf log4j2 über slf4j nach Code/zur Laufzeit:

import org.Apache.logging.log4j.LogManager;
import org.Apache.logging.log4j.core.LoggerContext;
import org.Apache.logging.log4j.core.config.Configuration;
import org.Apache.logging.log4j.core.config.LoggerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Log4j2OverSlf4jConfigurator {

    final private static Logger LOGGER = LoggerFactory.getLogger(Log4j2OverSlf4jConfigurator.class);

    public static void main(final String[] args) {
        LOGGER.info("Starting");
        LoggerContext loggerContext = (LoggerContext) LogManager.getContext();
        Configuration configuration = loggerContext.getConfiguration();

        LOGGER.info("Filepath: {}", configuration.getConfigurationSource().getLocation());
        // Log4j root logger has no name attribute -> name == ""
        LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("");

        rootLoggerConfig.getAppenders().forEach((name, appender) -> {
            LOGGER.info("Appender {}: {}", name, appender.getLayout().toString());
            // rootLoggerConfig.removeAppender(a.getName());
        });

        rootLoggerConfig.getAppenderRefs().forEach(ar -> {
            System.out.println("AppenderReference: " + ar.getRef());
        });

        // adding appenders
        configuration.addAppender(null);
    }
}

Referenz: https://logging.Apache.org/log4j/2.x/manual/customconfig.html

7
SilentMax

Ich denke, Sie haben ein ähnliches Szenario wie wir. Eine komplexere Protokollierung in der Produktion, aber eine einfachere während des JUnit-Tests, sodass wir feststellen können, dass keine Fehler aufgetreten sind.

Es gibt sauberere Lösungen, die Builder verwenden, wenn Sie log4j2> 2.4 verwenden (aber dann keine Unterstützung für Java6). Dies ist jedoch die, mit der ich mit log4j2 2.3 gearbeitet habe:

@Test
public void testClass() {
    LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);

    Configuration configuration = loggerContext.getConfiguration();
    LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("");
    ListAppender listAppender = new ListAppender("testAppender");

    rootLoggerConfig.addAppender(listAppender, Level.ALL, null);

    new TestClass();    //this is doing writing an error like org.slf4j.LoggerFactory.getLogger(TestClass.class).error("testing this");

    assertEquals(1, listAppender.getEvents().size());
}

Beachten Sie, dass wir beim Aufruf von getContext "false" übergeben müssen, da es anscheinend nicht den gleichen Kontext wie slf4j erhält.

3
lqbweb

Daniele, ein ListAppender existiert in Log4J-2.0 (Paket org.Apache.logging.log4j.test.appender). Es ist Teil der Distribution, aber es befindet sich im Log4j-Core-Test-Jar. Es wird hauptsächlich für JUnit-Tests verwendet. Die JUnit-Testquelle enthält auch Beispielkonfigurationen, die zeigen, wie mit diesem ListAppender konfiguriert wird. Eine Beispielkonfiguration sieht in etwa so aus:

<Configuration status="warn" packages="org.Apache.logging.log4j.test">
  <Appenders>
    <List name="MyList">
    </List>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="MyList"/>
    </Root>
  </Loggers>
</Configuration>
0
Remko Popma