使用slf4j和log4j2动态添加appender

Dan*_*ino 16 java logging slf4j log4j2

我想动态创建一个appender并将其添加到记录器.但是,这似乎不可能与slf4j.我可以将我的appender添加到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() );
      }

  }
Run Code Online (Sandbox Code Playgroud)

这是我非常基本的追随者:

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

  }
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能让它发挥作用?也许我从错误的角度接近这个,但我想避免创建我自己的记录器类.任何帮助是极大的赞赏.

Sil*_*Max 8

通过代码/在运行时访问和操作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);
    }
}
Run Code Online (Sandbox Code Playgroud)

参考:https://logging.apache.org/log4j/2.x/manual/customconfig.html

  • 这不适用于 slf4j,您需要像 getContext(false) 一样调用 getContext,否则您将获得不同的上下文。 (2认同)

lqb*_*web 5

我认为您的情况与我们类似。生产中的日志记录比较复杂,而在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());
}
Run Code Online (Sandbox Code Playgroud)

需要注意的重要一点是,调用getContext时我们需要传递“ false”,否则似乎无法获得与slf4j相同的上下文。

  • *“重要的是要注意,我们在调用 getContext 时需要传递“false”,否则似乎无法获得与 slf4j 相同的上下文。”* 啊,这在这里真的很重要! (3认同)

Rem*_*pma 0

Daniele,Log4J-2.0(包)中存在一个 ListAppender 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>
Run Code Online (Sandbox Code Playgroud)