web-dev-qa-db-ja.com

slf4jとlog4j2で動的にアペンダーを追加する

アペンダーを動的に作成してロガーに追加したい。ただし、これはslf4jでは可能ではないようです。アペンダーをlog4jロガーに追加できますが、slf4j LoggerFactoyでロガーを取得できません。

私がしたいこと:(jUnitテストではなく)テストクラスを作成し、テストクラスが使用するためにコンストラクターにロガーを渡します。テストクラスのすべてのインスタンスには、後でHTMLレポートで使用できるようにログを保存する独自のロガーとアペンダーが必要です。

私が試したこと(簡単にするために、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() );
      }

  }

これは私の非常に基本的なアペンダーです:

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

  }

これを機能させるにはどうすればよいですか?多分私は間違った角度からこれに取り組んでいますが、私は自分のロガークラスを作成することを避けたいです。どんな助けでも大歓迎です。

18
Daniele Torino

コード/実行時にslf4jを介してlog4j2にアクセスして操作する:

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

リファレンス: https://logging.Apache.org/log4j/2.x/manual/customconfig.html

8
SilentMax

あなたは私たちと同じようなシナリオを持っていると思います。本番環境ではより複雑なロギングですが、JUnitテスト中の方が簡単なので、エラーがないと断言できます。

Log4j2> 2.4を使用している場合はビルダーを使用したよりクリーンなソリューションがあります(ただし、Java6はサポートされていません)が、これは私が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());
}

GetContextを呼び出すときに「false」を渡す必要があることに注意してください。それ以外の場合は、slf4jと同じコンテキストを取得していないようです。

5
lqbweb

Daniele、ListAppenderはLog4J-2.0に存在します(パッケージorg.Apache.logging.log4j.test.appender)。これはディストリビューションの一部ですが、log4j-core-tests jarにあります。主にJUnitテストで使用されます。 JUnitテストソースには、このListAppenderで構成する方法を示すサンプル構成もあります。サンプル構成は次のようになります。

<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