Spring Boot日志输出统一增加线程信息

引言

在Spring Boot应用中,日志输出是非常重要的。为了更好地追踪日志,我们通常会在日志中增加线程信息。本文将教会刚入行的开发者如何实现在Spring Boot中统一增加线程信息的日志输出。

整体流程

下表展示了实现此功能的整体流程:

步骤 描述
1 导入相关依赖
2 创建自定义LoggerFilter
3 创建自定义Logback配置
4 配置logback-spring.xml
5 测试日志输出

接下来,我们将详细介绍每个步骤以及需要进行的操作。

步骤一:导入相关依赖

首先,我们需要在项目的pom.xml文件中导入以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 导入logback依赖 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
</dependency>

步骤二:创建自定义LoggerFilter

创建一个自定义的LoggerFilter类,用于将线程信息添加到日志中。可以参考以下代码:

import org.slf4j.MDC;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
import javax.servlet.http.HttpServletRequest;

public class ThreadInfoLoggerFilter extends AbstractRequestLoggingFilter {

    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        MDC.put("threadId", String.valueOf(Thread.currentThread().getId()));
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        MDC.remove("threadId");
    }
}

上述代码中,我们继承了AbstractRequestLoggingFilter类,重写了beforeRequest和afterRequest方法。在beforeRequest方法中,我们将当前线程的ID放入了MDC(Mapped Diagnostic Context)中,这样在日志输出时就可以获取到线程信息。在afterRequest方法中,我们移除了MDC中的threadId。

步骤三:创建自定义Logback配置

接下来,我们需要创建一个自定义的Logback配置类,用于指定日志输出格式和使用自定义的LoggerFilter。可以参考以下代码:

import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.encoder.Encoder;
import ch.qos.logback.core.status.InfoStatus;
import ch.qos.logback.core.status.StatusManager;
import ch.qos.logback.core.util.StatusPrinter;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import java.io.FileNotFoundException;

@Configuration
public class LogbackConfig implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 初始化LoggerContext
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        loggerContext.reset();

        // 创建ConsoleAppender
        ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
        consoleAppender.setName("CONSOLE");
        consoleAppender.setContext(loggerContext);
        consoleAppender.setEncoder(createEncoder(loggerContext));
        consoleAppender.start();

        // 创建FileAppender
        FileAppender<ILoggingEvent> fileAppender = new FileAppender<>();
        fileAppender.setName("FILE");
        fileAppender.setContext(loggerContext);
        fileAppender.setEncoder(createEncoder(loggerContext));
        fileAppender.setFile(ResourceUtils.getFile("classpath:logs/application.log").getPath());
        fileAppender.start();

        // 设置根Logger的Appender
        ch.qos.logback.classic.Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
        rootLogger.addAppender(consoleAppender);
        rootLogger.addAppender(fileAppender);
        rootLogger.setLevel(Level.INFO);

        // 打印Logback的内部状态
        StatusManager statusManager = loggerContext.getStatusManager();
        if