【问题标题】:Configuring logback.xml to output all log messages in one file or in separate file for each test, based on the Test configuration根据测试配置,配置 logback.xml 以将所有日志消息输出到一个文件或每个测试的单独文件中
【发布时间】:2017-10-09 07:25:11
【问题描述】:

我有五个 JUnit 测试要循环运行。 (知道 JUnit 参数化但暂时不使用它)

我想要的是,在运行测试之前,它会检查配置文件,其中有separeLogFile=true/false 的选项。如果该选项为真,则测试应为每个测试生成单独的日志文件,如果该选项为假,它将为所有五个测试仅生成一个日志文件。

我正在使用logback.xml 和 SL4J 记录器进行记录。目前它只为所有测试生成一个日志文件。

我很困惑如何以编程方式指定根据选项生成日志文件的位置/位置?有什么方法可以指定两个文件名和位置,并根据配置文件中的选项使logback.xml 从它们中进行选择?我第一次使用logback.xml

目前我的logback.xml 如下所示:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
        </pattern>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </encoder>
</appender>


<appender name="FILE"
          class="ch.qos.logback.core.rolling.RollingFileAppender">
    <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!-- Daily rollover -->
        <fileNamePattern>target/logs/Log_Test_%d{yyyy-MM-dd}.log
        </fileNamePattern>

        <!-- Keep 7 days' worth of history -->
        <maxHistory>7</maxHistory>
    </rollingPolicy>

    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
        </pattern>
    </encoder>
</appender>

<!-- Configure so that it outputs to both console and log file -->
<root level="INFO">
    <appender-ref ref="FILE"/>
    <appender-ref ref="STDOUT"/>
</root>

【问题讨论】:

    标签: java logging junit logback


    【解决方案1】:

    您可以使用 Logback 的 SiftingAppender 将日志定向到特定的日志文件。

    这是一个例子:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration debug="true">
    
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>
                    %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
                </Pattern>
            </layout>
        </appender>
    
        <appender name="SIFTER" class="ch.qos.logback.classic.sift.SiftingAppender">
            <discriminator>
                <key>testName</key>
                <defaultValue>ALL</defaultValue>
            </discriminator>
            <sift>
                <appender name="FILE-${testName}" class="ch.qos.logback.core.FileAppender">
                    <file>target/logs/Log_Test_${testName}.log</file>
    
                    <encoder>
                        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
                        </pattern>
                    </encoder>
                </appender>
            </sift>
        </appender>
    
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="SIFTER"/>
        </root>
    
    </configuration>
    

    使用此 Logback 配置,以下代码...

    String[] testNames = new String[] { "one", "two"};
    
    for (String testName : testNames) {
        MDC.put("testName", testName);
        logger.info("This message should go into the log file for {}", testName);
    }
    

    ... 将导致填充 两个 日志文件:

    ~/dev/code/stackoverflow/target/logs$ cat Log_Test_one.log 
    09:04:19.922 [main] INFO  SomeClassTest - This message should go into the log file for one
    ~/dev/code/stackoverflow/target/logs$ cat Log_Test_two.log 
    09:04:19.938 [main] INFO  SomeClassTest - This message should go into the log file for two
    

    还有下面的代码……

    String[] testNames = new String[] { "one", "two"};
    
    for (String testName : testNames) {
        logger.info("This message should go into the log file for {}", testName);
    }
    

    ... 将导致 一个 日志文件被填充:

    ~/dev/code/stackoverflow/target/logs$ cat Log_Test_ALL.log 
    09:06:54.009 [main] INFO  SomeClassTest - This message should go into the log file for one
    09:06:54.022 [main] INFO  SomeClassTest - This message should go into the log file for two
    

    因此,如果您在调用 logger.xxx() 之前填充 testName MDC 属性,那么日志事件将被筛选,即定向到以该 MDC 值命名的日志文件。如果您不填充 testName MDC 属性,则所有日志事件都将被定向到“ALL”日志文件。

    更新 1 回应此评论:

    好吧,我用你提供的那个替换了我原来的 File Appender 的整个块,但它根本没有生成日志文件..出了点问题。

    如果不查看您的所有配置,很难诊断出问题所在,因此我已更新此答案以包含完整的logback.xml,并且此配置已启用调试,因此您应该会看到类似...的输出...

    09:59:32,268 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [SIFTER]
    09:59:32,281 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.sift.MDCBasedDiscriminator] for [discriminator] property
    09:59:32,298 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to INFO
    09:59:32,298 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
    09:59:32,304 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [SIFTER] to Logger[ROOT]
    ...
    09:59:34,725 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.FileAppender]
    09:59:34,730 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [FILE-one]
    ...
    09:59:34,732 |-INFO in ch.qos.logback.core.FileAppender[FILE-one] - File property is set to [target/logs/Log_Test_one.log]
    

    ... 显示正在运行的筛选附加程序。

    【讨论】:

    • 感谢故障。这可能正是我正在寻找的。当我写这个 SIFTER appender 时,我应该删除 File Appender 吗?如果不是那么我怎么能同时写两个?我两个都写了,没用!
    • SiftingAppender 包装 FileAppender,因此您不需要单独的 FileAppender。您可以使用我提供的示例;它按原样工作。我建议从我的示例开始,一旦你让它工作,然后在你认为合适的情况下更改 SiftingAppender 中的 FileAppender。
    • 好吧,我用你提供的那个替换了我原来的 File Appender 的整个块,但它根本没有生成日志文件..出了点问题。
    • 我已经用完整的 logback.xml 更新了答案,请尝试并阅读答案的最后一部分 - 它也描述了 Logback 的调试输出。
    • Glitch,我发现它总是采用 Key 的 defaultValu 而不是来自变量 TestName,例如所以 MDC.put("tesName", Integer.toString(test));不管用。 test 对我来说是一个整数,因此将其转换为字符串..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    相关资源
    最近更新 更多