在企业级系统中,记录每一次 API 调用的详细信息(包括请求耗时、参数、IP、异常等)是非常重要的,无论是为了问题排查、性能优化还是审计追踪。本篇文章将手把手带你通过拦截器 + logback 自定义日志文件,实现高性能、高可读性的 API 访问日志记录。
✅ 实现目标
- 每次 HTTP 请求都被记录日志
- 记录内容包括:URL、方法、参数、请求 IP、耗时
- 根据耗时分类:FAST、NORMAL、SERIOUS
- 将日志写入专属日志文件
track.log,不影响主业务日志 - 可支持 JSON 格式输出,方便 ELK/SLS 分析
🧱 步骤一:定义日志数据模型 MTrackLog
import lombok.Data;
import java.io.Serializable;
@Data
public class MTrackLog implements Serializable {
private String url;
private String method;
private long start;
private long end;
private String remoteIp;
private String parameter;
@Override
public String toString() {
long cost = end - start;
String level = cost >= 1500 ? "SERIOUS" : (cost > 300 ? "NORMAL" : "FAST");
return String.format(
"{"url":"%s", "method":"%s", "cost":%d, "level":"%s", "ip":"%s", "param":"%s"}",
url, method, cost, level, remoteIp, parameter
);
}
}
✅ 可以根据实际需求加入
traceId、userId等字段。
🔧 步骤二:自定义拦截器记录请求信息
@Component
public class RequestTrackInterceptor implements HandlerInterceptor {
private static final Logger trackLogger = LoggerFactory.getLogger("TRACK_FILE_NAME");
private static final String TRACK_LOG_KEY = "_trackLog";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
MTrackLog mTrackLog = new MTrackLog();
mTrackLog.setStart(System.currentTimeMillis());
request.setAttribute(TRACK_LOG_KEY, mTrackLog);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
Object obj = request.getAttribute(TRACK_LOG_KEY);
if (obj instanceof MTrackLog mTrackLog) {
mTrackLog.setEnd(System.currentTimeMillis());
mTrackLog.setMethod(request.getMethod());
mTrackLog.setUrl(request.getRequestURL().toString());
mTrackLog.setRemoteIp(request.getRemoteAddr());
String parameter;
if ("GET".equalsIgnoreCase(request.getMethod())) {
parameter = request.getQueryString();
} else if (new StandardServletMultipartResolver().isMultipart(request)) {
parameter = "multipart";
} else {
try {
parameter = new CustomHttpServletRequestWrapper(request).getBody();
} catch (Exception e) {
parameter = "error_reading_body";
}
}
mTrackLog.setParameter(parameter);
trackLogger.info(mTrackLog.toString());
}
}
}
🧩 步骤三:注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RequestTrackInterceptor requestTrackInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestTrackInterceptor).addPathPatterns("/**");
}
}
📦 步骤四:logback-spring.xml 日志配置
<!-- 跟踪日志输出到独立文件 -->
<appender name="TRACK_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/track.%d{yyyyMMdd}.%i.log.gz</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern> <!-- 输出格式为纯内容 JSON -->
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="TRACK_FILE_NAME" level="INFO" additivity="false">
<appender-ref ref="TRACK_FILE"/>
</logger>
📋 示例输出日志
{"url":"/api/user", "method":"GET", "cost":102, "level":"FAST", "ip":"192.168.1.101", "param":"id=1001"}
{"url":"/api/order", "method":"POST", "cost":1580, "level":"SERIOUS", "ip":"192.168.1.10", "param":"{"userId":10}"}
🧠 小结
这种方式通过 拦截器 + 自定义日志对象 + logback 多日志文件输出 的组合,可以实现一个:
- 高性能
- 高可读性
- 易于追踪与分析
的 API 日志追踪机制,非常适合中大型项目使用,特别是微服务场景中每个服务需要独立输出访问日志时。
如果你想继续拓展,还可以考虑:
- 加入 TraceId(链路追踪)
- 整合 MDC 实现日志链路穿透
- 配合 ELK/SLS 实现实时查询和报警
如果这篇文章对你有帮助,欢迎点赞、收藏、关注我获取更多 Spring Boot 实战技巧!