企业系统开发记录API调用的详细信息是件非常重要的活,当排查系统问题、优化性能,还是进行审计追踪,这些日志能派上大用场。今天这篇文章,就来教大家怎么用Spring Boot实现API请求的自定义日志记录,还会涉及性能分析和日志分类!

一、明确实现目标

我们要达成的效果具体有这些:

  1. 每次HTTP请求都得记录日志,一个都不能漏。
  2. 日志里要包含URL、请求方法、请求参数、请求IP以及请求耗时这些关键信息。
  3. 根据请求耗时对日志进行分类,分为“FAST”(快速)、“NORMAL”(正常)、“SERIOUS”(严重,耗时较长)三类。
  4. 把这些日志单独写入一个叫track.log的专属日志文件里,这样就不会和主业务日志混在一起,方便查看和管理。
  5. 支持以JSON格式输出日志,这样用ELK、SLS这些工具做数据分析的时候就更方便了。

二、搭建日志数据模型MTrackLog

第一步,我们得定义一个日志数据模型,用来存放要记录的信息。这里创建一个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 ); } } 

这个类里定义了URL、请求方法、请求开始和结束时间、请求IP、请求参数这些属性。toString方法是用来把这些信息按照我们想要的格式输出,根据请求耗时划分等级,最后拼成一个JSON格式的字符串。大家要是有其他需求,还能往里面加traceIduserId这些字段。

三、自定义拦截器记录请求详情

接下来,我们写一个自定义拦截器,用来记录每次请求的详细信息。代码如下:

@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()); } } } 

preHandle方法里,每次请求开始时,我们创建一个MTrackLog对象,记录下开始时间,然后把这个对象存到请求里。等请求处理完,在afterCompletion方法里,我们再从请求里取出这个对象,补充上请求结束时间、请求方法、URL、请求IP和请求参数这些信息,最后把日志记录下来。这里获取请求参数的时候,会根据请求方法的不同来处理,如果是GET请求,直接取查询字符串;如果是文件上传这种multipart请求,就标记为multipart;其他情况就尝试读取请求体。

四、注册拦截器让其生效

写好拦截器后,还得注册一下,这样它才能在请求过程中起作用。注册拦截器的代码如下:

@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private RequestTrackInterceptor requestTrackInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(requestTrackInterceptor).addPathPatterns("/**"); } } 

这段代码很简单,就是在配置类里把我们写好的RequestTrackInterceptor注册到Spring的拦截器链里,并且设置它拦截所有的请求路径。

五、配置logback-spring.xml日志文件

最后,我们要配置一下日志文件,让日志能按我们的要求输出到指定文件里。在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> 

这段配置的意思是,创建一个叫TRACK_FILE的日志输出器,它会按照时间和文件大小滚动生成日志文件。日志的输出格式是纯JSON内容,并且只记录INFO级别的日志。然后把这个日志输出器和TRACK_FILE_NAME这个日志记录器关联起来,这样日志就会输出到指定的文件里了。

六、看看示例输出日志长啥样

配置好之后,日志输出的样子大概是这样:

{"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的实战技巧!