如何为非200 HTTP响应单独记录请求方法、路径等信息?
问题解答
仅通过logback-spring.xml修改ERROR日志类型无法实现需求
Logback本身无法直接获取Spring MVC请求的方法、路径、响应状态码这类业务上下文信息——这些数据属于Spring Web的请求生命周期数据,必须先通过Spring的拦截机制收集后传递给日志框架,单纯修改Logback配置无法完成数据采集与关联。
可行实现方式:Spring拦截器 + Logback配置结合
通过Spring拦截器捕获非200响应的请求信息,配合Logback过滤输出到单独日志文件,既满足需求又不会污染其他日志。
1. 自定义Spring拦截器收集请求响应信息
创建拦截器,在请求结束后判断响应状态码,非200时将关键信息存入MDC并触发特定标记的日志,之后清空MDC避免影响后续请求:
import org.slf4j.MDC; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Non200ResponseLoggingInterceptor implements HandlerInterceptor { private static final String LOG_MARKER = "NON_200_RESPONSE"; @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { int status = response.getStatus(); if (status != 200) { String method = request.getMethod(); String path = request.getRequestURL().toString(); String responseStatus = status + " " + getStatusText(status); MDC.put("requestMethod", method); MDC.put("requestPath", path); MDC.put("responseStatus", responseStatus); // 触发带标记的日志 org.slf4j.LoggerFactory.getLogger(getClass()).error("{}", LOG_MARKER); MDC.clear(); } } private String getStatusText(int status) { switch (status) { case 400: return "BAD_REQUEST"; case 401: return "UNAUTHORIZED"; case 403: return "FORBIDDEN"; case 404: return "NOT_FOUND"; case 500: return "INTERNAL_SERVER_ERROR"; default: return "UNKNOWN_STATUS"; } } }
注册拦截器:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new Non200ResponseLoggingInterceptor()); } }
2. 配置logback-spring.xml实现单独日志输出
配置专属Appender,过滤带标记的日志并格式化输出:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 控制台输出基础日志 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 非200响应专属日志Appender --> <appender name="NON_200_RESPONSE" class="ch.qos.logback.core.FileAppender"> <file>logs/non-200-responses.log</file> <encoder> <pattern>method: %X{requestMethod}, path: %X{requestPath}, response: %X{responseStatus}%n</pattern> </encoder> <!-- 过滤带指定标记的日志 --> <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> <evaluator> <expression>message.contains("NON_200_RESPONSE")</expression> </evaluator> <OnMatch>ACCEPT</OnMatch> <OnMismatch>DENY</OnMismatch> </filter> </appender> <!-- 根日志配置 --> <root level="info"> <appender-ref ref="CONSOLE"/> </root> <!-- 拦截器日志单独输出,避免重复打印到控制台 --> <logger name="com.yourpackage.Non200ResponseLoggingInterceptor" level="error" additivity="false"> <appender-ref ref="NON_200_RESPONSE"/> </logger> </configuration>
3. 核心逻辑说明
- 拦截器仅在非200响应时触发日志,通过MDC传递请求响应信息
- Logback通过标记过滤出目标日志,格式化后写入单独文件
additivity="false"确保该日志不会重复输出到根Logger的Appender(如控制台)
内容的提问来源于stack exchange,提问作者Cristian Hreceniuc
相关产品推荐
相关产品推荐

