【问题标题】:How to run jul-to-slf4j bridge once per JVM?如何为每个 JVM 运行一次 jul-to-slf4j 桥接?
【发布时间】:2016-05-19 20:09:00
【问题描述】:

我想以并行模式(多个 JVM)运行 Surefire,每个 JVM 都必须运行:

SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();

在第一次测试之前正好一次。如何做到这一点?

【问题讨论】:

    标签: junit testng slf4j surefire


    【解决方案1】:

    有多种方法可以让一些代码在测试套件的开头运行。

    这里有 4 个(我相信还有更多):

    1. JUnit 通过RunWith SuiteSuite.SuiteClassesBeforeClass(改编自SuiteTest 中的示例):

      @RunWith(Suite.class)
      @SuiteClasses({FirstTest.class, SecondTest.class/*, ...*/, LastTest.class})
      public static class AllWithSLF4JBridgeHandler {
          @BeforeClass
          public static void registerRootLoggerHandlers() {
              SLF4JBridgeHandler.removeHandlersForRootLogger();
              SLF4JBridgeHandler.install();
          }
      }
      
    2. 使用BeforeSuite 进行测试:

      /**
       * Base class for each test class (i.e. every test class should extend this class).
       */
      public abstract class BaseTest {
          @BeforeSuite
          public void registerRootLoggerHandlers() {
              SLF4JBridgeHandler.removeHandlersForRootLogger();
              SLF4JBridgeHandler.install();
          }
      }
      
    3. 使用Guice 进行测试:

      /**
       * Test module. Each test class should be annotated with `@Guice(TestModule.class)`.
       */
      public class TestModule implements Module {
          @Override
          public void configure(Binder binder) {
              SLF4JBridgeHandler.removeHandlersForRootLogger();
              SLF4JBridgeHandler.install();
          }
      }
      
    4. Static initialization blocks(独立于测试框架):

      /**
       * Base class for each test class (i.e. every test class should extend this class).
       */
      public abstract class BaseTest {
          static {
              SLF4JBridgeHandler.removeHandlersForRootLogger();
              SLF4JBridgeHandler.install();
          }
      }
      

    我不确定所有这些方法如何与 Surefire 的并行模式一起工作。方法 1 和 2 可能在那里不起作用,但我相信方法 3 和 4 应该。


    另一种选择是不使用SLF4JBridgeHandler 的编程安装,而是使用java.util.logging.config 文件或类(参见LogManager):

    1. “java.util.logging.config.file”:

      logging.properties 文件:

      // register SLF4JBridgeHandler as handler for the j.u.l. root logger
      handlers = org.slf4j.bridge.SLF4JBridgeHandler
      

      系统属性赋值:

      java -Djava.util.logging.config.file=/path/to/logging.properties ...
      

      如果您事先知道日志文件的路径,这会很好。

    2. “java.util.logging.config.class”:

      如果您正在部署 WAR 并且不知道文件将在哪里等,则使用文件可能不是一个好的选择,因此您也可以创建一个日志记录配置类:

      public class SLF4JBridgeHandlerInitializer {
          public SLF4JBridgeHandlerInitializer() throws IOException {
              String loggingConfigurationString = "handlers = " + SLF4JBridgeHandler.class.getName();
              InputStream inputStream = new ByteArrayInputStream(loggingConfigurationString.getBytes());
              LogManager.getLogManager().readConfiguration(inputStream);
          }
      }
      

      系统属性赋值:

      java -Djava.util.logging.config.class=package.SLF4JBridgeHandlerInitializer ...
      

      我以前做过,对我来说效果很好 (SLF4JBridgeHandler.Initializer by mfulton26 · Pull Request #57 · qos-ch/slf4j)。

    只要设置了适当的系统属性,这最后两个选项就应该初始化每个 JVM 实例。

    【讨论】:

    • 感谢您的全面回答。
    猜你喜欢
    • 2014-12-31
    • 1970-01-01
    • 2016-01-13
    • 2016-04-01
    • 2015-09-13
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多