如何使用Spring Boot实现API请求日志记录和性能分析

后端 潘老师 4小时前 6 ℃ (0) 扫码查看

企业系统开发记录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的实战技巧!


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/back/18113.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】