如何 运行 每个 JVM 桥接一次 jul-to-slf4j?

How to run jul-to-slf4j bridge once per JVM?

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

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

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

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

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

  1. JUnit 通过 RunWith Suite with Suite.SuiteClasses and BeforeClass (adapted from examples in 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. TestNG 与 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. TestNG 与 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 文件或 class(参见 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 并且不知道该文件在哪里等等,那么使用文件可能不是一个好的选择,因此您也可以创建一个日志配置 class:

    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 实例。