Spring 引导 - @Slf4j 日志记录行为在测试和实际应用程序中有所不同

Spring Boot - @Slf4j Logging Behavior differs in Test and in real Application

我有一个这样的样本class,

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TestLogging {

    public void printLogLevel(){

        if(log.isErrorEnabled()){
            log.error("Error Enabled");
        }

        if(log.isTraceEnabled()){
            log.trace("Trace Enabled");
        }

        if(log.isInfoEnabled()){
            log.info("Info Enabled");
        }

        if(log.isDebugEnabled()){
            log.debug("DEBUG enabled");
        }
    }
}

我写过这样的测试用例,

import org.junit.Test;

public class TestLoggingTest {
    TestLogging testLogging = new TestLogging();

    @Test
    public void testLoggingLevel(){
        testLogging.printLogLevel();
    }
}

当我 运行 这个测试时,下面的项目被打印到控制台。

19:48:54.661 [main] ERROR com.tejas.springlogging.TestLogging - Error Enabled
19:48:54.665 [main] INFO com.tejas.springlogging.TestLogging - Info Enabled
19:48:54.666 [main] DEBUG com.tejas.springlogging.TestLogging - DEBUG enabled

但是当我 运行 来自这样的应用程序的 printLogLevel() 时,

@SpringBootApplication
@Slf4j
public class SpringLoggingApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringLoggingApplication.class, args);

        TestLogging testLogging = new TestLogging();
        testLogging.printLogLevel();
    }

}

以下行被打印到控制台。

2021-10-12 20:05:27.183 ERROR 8924 --- [           main] com.tejas.springlogging.TestLogging      : Error Enabled
2021-10-12 20:05:27.183  INFO 8924 --- [           main] com.tejas.springlogging.TestLogging      : Info Enabled

以下是我用于此测试的依赖项。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>optional</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.hamcrest</groupId>
                    <artifactId>hamcrest-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

这是父 pom 版本。

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

现在的问题是,为什么当我从测试和从应用程序调用 printLogLevel() 方法时存在差异。调试级别仅从测试中打印出来。我可以知道为什么吗?

编辑:按照@narendra 的建议添加@SpringBootTest 修复了这个问题,但它仅适用于 junit5。我想要 junit4

中的修复

在应用程序中,它在 Spring 应用程序上下文中使用 Slf4j,因此它使用 Spring 的默认模式进行日志记录。默认日志级别为 INFO.

参见 Log Format Spring。

此模式不同于 SLF4j default pattern

With no configuration, the default output includes the relative time in milliseconds, thread name, the level, logger name, and the message followed by the line separator for the host. In log4j terms it amounts to the "%r [%t] %level %logger - %m%n" pattern. Sample output follows.

 176 [main] INFO examples.Sort - Populating an array of 2 elements in reverse order.  
 225 [main] INFO examples.SortAlgo - Entered the sort method.
 304 [main] INFO examples.SortAlgo - Dump of integer array:
 317 [main] INFO examples.SortAlgo - Element [0] = 0

默认日志级别将取决于普通 SLF4j 日志记录器的初始化。


解决方案: 你可以添加SpringBootTest来测试class统一日志模式。

@Slf4j注解与Spring无关。它是一个在编译期间生效的 lombok 注释(而 spring boot 是一个运行时框架)。 所以放置这个注解基本上与放置一个静态字段相同,该字段保存对初始化 slf4j 记录器的引用。

现在 slf4j 本身不打印任何东西,而是依赖于底层的日志库,这些库实际上能够打印实际的日志消息。

因此,更改是您在应用程序的源代码中有类似 logback-spring.xmllogback.xml 的东西,以及 SLF4J 委托从中初始化的日志记录框架。 Spring boot 在日志记录方面也有一些合理的默认值。 由于 spring boot 还可以与 log4j2 集成,因此很难判断您的应用程序中到底发生了什么,因此您应该检查一下。

现在,在测试的时候,情况就不同了。您展示了一个与 spring 无关的单元测试。因此它在启用 slf4j 的情况下“自行”运行。

记录器的实际行为再次取决于您如何配置 slf4j 进行测试。