如何在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
相关产品推荐
相关产品推荐

