web-dev-qa-db-fra.com

Ajouter dynamiquement un appender avec slf4j et log4j2

Je veux créer dynamiquement un appender et l'ajouter à un enregistreur. Cependant, cela ne semble pas être possible avec slf4j. Je peux ajouter mon appender à un enregistreur log4j, mais je n'arrive pas à récupérer cet enregistreur avec le loggerFactoy slf4j.

Ce que je veux faire: je crée une classe de test (pas un test jUnit) et passe un consignateur dans le constructeur à utiliser par la classe de test. Chaque instance de la classe de test a besoin de son propre consignateur et de son appender qui enregistre le journal afin qu'il puisse être utilisé ultérieurement dans un rapport HTML.

Ce que j'ai essayé (pour des raisons de simplicité, j'ai créé un test jUnit):

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

  }

et ceci est mon très basique 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));
      }

  }

Que puis-je faire pour que cela fonctionne? Peut-être que j'aborde ce problème sous le mauvais angle, mais j'aimerais éviter de créer ma propre classe de consignateurs. Toute aide est grandement appréciée.

13
Daniele Torino

Accéder à et manipuler log4j2 sur slf4j par code/au moment de l’exécution:

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

Référence: https://logging.Apache.org/log4j/2.x/manual/customconfig.html

7
SilentMax

Je pense que vous rencontrez un scénario similaire au nôtre. Une journalisation plus complexe en production, mais plus simple lors des tests JUnit, afin de pouvoir affirmer qu’il n’ya pas eu d’erreurs.

Il existe des solutions plus propres utilisant des générateurs si vous utilisez log4j2> 2.4 (mais alors, aucun support pour Java6), mais c’est celui que j’ai utilisé avec log4j2 2.3:

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

Il est important de noter que nous devons passer "false" lorsque nous appelons getContext, car sinon, il semble que le contexte ne soit pas identique à celui de slf4j.

3
lqbweb

Daniele, un ListAppender existe dans Log4J-2.0 (package org.Apache.logging.log4j.test.appender). Cela fait partie de la distribution, mais cela se trouve dans le fichier jar log4j-core-tests. Il est principalement utilisé pour les tests JUnit. La source de test JUnit a également des exemples de configuration montrant comment configurer avec cet ListAppender. Un exemple de configuration ressemble à ceci:

<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