You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot应用中记录REST API请求响应指标及错误JSON日志?

Spring Boot API请求响应JSON日志实现方案

推荐库及配置方法

1. Zalando Logbook(开箱即用的专业HTTP日志库)

Logbook是专注于HTTP请求/响应日志的轻量级库,支持自定义格式、异常捕获、执行时长统计,完全匹配你的需求。

集成步骤:

  • 添加Maven依赖:
<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-spring-boot-starter</artifactId>
    <version>2.20.0</version> <!-- 使用最新稳定版 -->
</dependency>
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>7.4</version>
</dependency>
  • 自定义日志字段配置:
    创建LogbookConfig类注入需要的日志字段,适配目标JSON格式:
import org.zalando.logbook.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Configuration
public class LogbookConfig {

    @Bean
    public LogbookCustomizer logbookCustomizer() {
        return logbook -> logbook
                .processor(new Processor() {
                    @Override
                    public HttpRequest process(HttpRequest request) {
                        // 记录请求时间戳
                        request.putAttribute("timestamp_log", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
                        request.putAttribute("start_time", System.currentTimeMillis());
                        return request;
                    }

                    @Override
                    public HttpResponse process(HttpResponse response) {
                        // 计算执行时长
                        long startTime = (long) response.getRequest().getAttribute("start_time");
                        long executionTime = System.currentTimeMillis() - startTime;
                        
                        // 填充日志字段
                        response.putAttribute("timestamp_log", response.getRequest().getAttribute("timestamp_log"));
                        response.putAttribute("request_type", response.getRequest().getMethod());
                        response.putAttribute("statusCode", String.valueOf(response.getStatus()));
                        response.putAttribute("execution_time_milliseconds", executionTime);
                        
                        // 错误分类与类型处理
                        if (response.getStatus() >= 400) {
                            Throwable exception = (Throwable) response.getRequest().getAttribute("exception");
                            if (exception != null) {
                                response.putAttribute("error classification", "Technical");
                                response.putAttribute("error_type", exception.getClass().getSimpleName());
                            } else {
                                response.putAttribute("error classification", "Functional");
                                response.putAttribute("error_type", "NOT SPECIFIED");
                            }
                        } else {
                            response.putAttribute("error classification", "NONE");
                            response.putAttribute("error_type", "NOT SPECIFIED");
                        }
                        return response;
                    }
                })
                .sink(new JsonSink(Logbook.DEFAULT_WRITER));
    }
}
  • Logback输出JSON配置:
    在logback-spring.xml中配置JSON编码器:
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>

    <logger name="org.zalando.logbook" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

2. 自定义过滤器 + Logback(完全灵活可控)

如果需要高度定制日志逻辑,可自行编写过滤器捕获请求响应数据,结合MDC(映射诊断上下文)输出JSON日志。

实现步骤:

  • 编写自定义过滤器:
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class RequestResponseLoggingFilter extends OncePerRequestFilter {

    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        long startTime = System.currentTimeMillis();
        String timestamp = LocalDateTime.now().format(DATE_FORMATTER);
        String requestType = request.getMethod();

        try {
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            MDC.put("error classification", "Technical");
            MDC.put("error_type", e.getClass().getSimpleName());
            throw e;
        } finally {
            long executionTime = System.currentTimeMillis() - startTime;
            int statusCode = response.getStatus();
            
            // 填充MDC字段
            MDC.put("timestamp_log", timestamp);
            MDC.put("request_type", requestType);
            MDC.put("statusCode", String.valueOf(statusCode));
            MDC.put("execution_time_milliseconds", String.valueOf(executionTime));

            // 处理无异常的错误场景
            if (statusCode >= 400 && !MDC.containsKey("error classification")) {
                MDC.put("error classification", "Functional");
                MDC.put("error_type", "NOT SPECIFIED");
            } else if (statusCode < 400) {
                MDC.put("error classification", "NONE");
                MDC.put("error_type", "NOT SPECIFIED");
            }

            // 输出日志
            logger.info("API Request/Response Log");
            // 清除MDC避免线程污染
            MDC.clear();
        }
    }
}
  • 注册过滤器:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<RequestResponseLoggingFilter> loggingFilter() {
        FilterRegistrationBean<RequestResponseLoggingFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new RequestResponseLoggingFilter());
        registrationBean.addUrlPatterns("/*"); // 捕获所有API请求
        return registrationBean;
    }
}
  • Logback配置同Logbook方案,使用logstash-logback-encoder输出JSON格式。

3. Spring Boot Actuator + Micrometer(监控+日志一体化)

如果项目已使用Actuator做监控,可通过HttpTrace功能捕获请求响应数据,配合Micrometer导出为JSON日志。

集成步骤:

  • 添加依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-logging</artifactId>
</dependency>
  • 开启HttpTrace:
    在application.yml中配置:
management:
  endpoints:
    web:
      exposure:
        include: httptrace
  trace:
    http:
      enabled: true
  • 自定义日志输出格式:
import org.springframework.boot.actuate.trace.http.HttpTrace;
import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
import org.springframework.stereotype.Component;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.format.DateTimeFormatter;

@Component
public class CustomHttpTraceRepository implements HttpTraceRepository {

    private final ObjectMapper objectMapper = new ObjectMapper();
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    @Override
    public List<HttpTrace> findAll() {
        return List.of();
    }

    @Override
    public void add(HttpTrace trace) {
        try {
            LogEntry logEntry = new LogEntry(trace);
            logger.info(objectMapper.writeValueAsString(logEntry));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class LogEntry {
        private String timestamp_log;
        private String request_type;
        private String statusCode;
        private String error_classification;
        private String error_type;
        private long execution_time_milliseconds;

        public LogEntry(HttpTrace trace) {
            this.timestamp_log = trace.getTimestamp().format(DATE_FORMATTER);
            this.request_type = trace.getRequest().getMethod();
            this.statusCode = String.valueOf(trace.getResponse().getStatus());
            this.execution_time_milliseconds = trace.getTimeTaken();
            
            if (trace.getResponse().getStatus() >= 400) {
                this.error_classification = "Functional";
                this.error_type = "NOT SPECIFIED";
            } else {
                this.error_classification = "NONE";
                this.error_type = "NOT SPECIFIED";
            }
        }

        // 生成getter方法
    }
}

总结

  • Zalando Logbook:最推荐,开箱即用,配置简单,无需大量自定义代码即可满足需求。
  • 自定义过滤器:适合需要高度定制日志内容、流程的场景。
  • Actuator + Micrometer:适合已有监控体系的项目,可实现监控与日志联动。

内容的提问来源于stack exchange,提问作者Keerthana Hemachandran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 23:49:50