SpringBoot 统计更多Api接口日志信息

这篇具有很好参考价值的文章主要介绍了SpringBoot 统计更多Api接口日志信息。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

第1步:基本配置了解

Further Reading : SpringBoot 统计API接口用时该使用过滤器还是拦截器?

第2步:丰富LogInterceptor(主体流程)

日志打印放afterCompletion是为了兼容异常场景也可以记录日志

import com.zhangziwa.practisesvr.utils.log.LogContext;
import com.zhangziwa.practisesvr.utils.log.ThreadMXBeanUtils;
import com.zhangziwa.practisesvr.utils.log.logUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.time.Instant;

@Component
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.err.println("***LogInterceptor.preHandle***");

        LogContext.setTraceId(logUtils.genUUID());
        LogContext.initSqlCost();
        LogContext.initSqlCost();
        if (Boolean.TRUE.equals(ThreadMXBeanUtils.isThreadCpuTimeEnabled())) {
            LogContext.initCurrentThreadTime();
            LogContext.initCurrentThreadUserTime();
        }
        if (Boolean.TRUE.equals(ThreadMXBeanUtils.isThreadAllocatedMemoryEnabled())) {
            LogContext.initAllocatedBytes();
        }

        long startTime = Instant.now().toEpochMilli();
        request.setAttribute("startTime", startTime);

        log.warn("LogInterceptor.postHandle: Start processing request at {} - {}", Instant.now(), request.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.err.println("***LogInterceptor.postHandle***");
        // 获取请求开始时间
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.err.println("***LogInterceptor.afterCompletion***");

        // 获取请求开始时间
        Long startTime = (Long) request.getAttribute("startTime");
        long executionCost = 0L;
        if (startTime != null) {
            executionCost = Instant.now().toEpochMilli() - startTime;
            int statusCode = response.getStatus();
            log.warn("LogInterceptor.postHandle: Finished processing request at {} - {} in {} ms. Status code: {}", Instant.now(), request.getRequestURI(), executionCost, statusCode);
        }

        String apiJson = logUtils.buildApiJsonLog(request, response, executionCost);
        log.info(apiJson);
        LogContext.clear();
    }
}

第3步:细枝末节功能介绍

3.1、引入LogContext收纳上下文数据

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class LogContext {
    private static ThreadLocal<AtomicInteger> sql_count = new InheritableThreadLocal<>();
    private static ThreadLocal<AtomicLong> sql_cost = new InheritableThreadLocal<>();
    private static ThreadLocal<String> traceid = new InheritableThreadLocal<>();
    private static ThreadLocal<Long> acclocated_memory = new InheritableThreadLocal<>();
    private static ThreadLocal<Long> total_cpu_cost = new InheritableThreadLocal<>();
    private static ThreadLocal<Long> user_cpu_cost = new InheritableThreadLocal<>();

    public static void initSqlCount() {
        sql_count.set(new AtomicInteger(0));
    }

    public static void incrementSqlCount() {
        if (sql_count.get() == null) {
            sql_count.set(new AtomicInteger(0));
        }
        sql_count.get().incrementAndGet();
    }

    public static int getSqlCount() {
        return sql_count.get().intValue();
    }

    public static void initSqlCost() {
        sql_cost.set(new AtomicLong(0));
    }

    public static void incrementSqlCost(Long sqlCost) {
        if (sql_cost.get() == null) {
            sql_cost.set(new AtomicLong(0));
        }
        sql_cost.get().addAndGet(sqlCost);
    }

    public static Long getSqlCost() {
        return sql_cost.get().longValue();
    }

    public static void setTraceId(String traceId) {
        if (traceid.get() == null) {
            traceid.set(traceId);
        }
    }

    public static String getTraceId() {
        return traceid.get();
    }

    public static void initAllocatedBytes() {
        acclocated_memory.set(ThreadMXBeanUtils.getCurrentThreadAllocatedBytes());
    }

    public static void initCurrentThreadTime() {
        total_cpu_cost.set(ThreadMXBeanUtils.getCurrentThreadTime());
    }

    public static void initCurrentThreadUserTime() {
        user_cpu_cost.set(ThreadMXBeanUtils.getCurrentThreadUserTime());
    }

    public static void clear() {
        sql_count.remove();
        sql_cost.remove();
        traceid.remove();
        acclocated_memory.remove();
        total_cpu_cost.remove();
        user_cpu_cost.remove();
    }
}

3.2、引入CPU使用统计

配置文件可以配置是否开启统计文章来源地址https://www.toymoban.com/news/detail-817809.html

thread:
  cpu_time_enabled: true
  allocated_memory_enabled: true
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class ThreadMXBeanConfig implements InitializingBean {
    @Value("${thread.cpu_time_enabled:true}")
    private static boolean isThreadCpuTimeEnabled;
    @Value("${thread.allocated_memory_enabled:true}")
    private static boolean isThreadAllocatedMemoryEnabled;

    @Override
    public void afterPropertiesSet() throws Exception {
        if (isThreadCpuTimeEnabled) {
            ThreadMXBeanUtils.setThreadCpuTimeEnabled(true);
        }
        if (isThreadAllocatedMemoryEnabled) {
            ThreadMXBeanUtils.setThreadAllocatedMemoryEnabled(true);
        }
    }
}
import com.sun.management.ThreadMXBean;
import java.lang.management.ManagementFactory;

public class ThreadMXBeanUtils {
    private static final ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();

    public static void setThreadCpuTimeEnabled(boolean enabled) {
        threadMXBean.setThreadCpuTimeEnabled(enabled);
    }

    public static void setThreadAllocatedMemoryEnabled(boolean enabled) {
        threadMXBean.setThreadAllocatedMemoryEnabled(enabled);
    }

    public static Boolean isThreadCpuTimeEnabled() {
        return threadMXBean.isThreadCpuTimeEnabled();
    }

    public static Boolean isThreadAllocatedMemoryEnabled() {
        return threadMXBean.isThreadAllocatedMemoryEnabled();
    }

    public static long getCurrentThreadTime() {
        return threadMXBean.getCurrentThreadCpuTime() / 1_000_000L;
    }

    public static long getCurrentThreadUserTime() {
        return threadMXBean.getCurrentThreadUserTime() / 1_000_000L;
    }

    public static long getCurrentThreadAllocatedBytes() {
        return threadMXBean.getCurrentThreadAllocatedBytes();
    }
}

3.3、拼接日志信息

import com.zhangziwa.practisesvr.utils.JsonUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;

public class logUtils {
    public static String genUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    public static String buildApiJsonLog(HttpServletRequest request, HttpServletResponse response, long cost) {
        Map<String, Object> apiJsonMap = new LinkedHashMap<>();
        apiJsonMap.put("traceId", LogContext.getTraceId());
        apiJsonMap.put("end_date", DateTimeFormatter.ISO_ZONED_DATE_TIME.format(ZonedDateTime.now()));
        apiJsonMap.put("cost", cost);
        apiJsonMap.put("remoteHost", request.getRemoteHost());
        apiJsonMap.put("remoteAddr", request.getRemoteAddr());
        apiJsonMap.put("remotePort", request.getRemotePort());
        apiJsonMap.put("method", request.getMethod());
        apiJsonMap.put("requestURI", request.getRequestURI());
        apiJsonMap.put("status", response.getStatus());
        apiJsonMap.put("requestContentLength", request.getContentLengthLong());
        apiJsonMap.put("sql_count", LogContext.getSqlCost());
        if (Boolean.TRUE.equals(ThreadMXBeanUtils.isThreadCpuTimeEnabled())) {
            apiJsonMap.put("currentThreadTime", ThreadMXBeanUtils.getCurrentThreadTime());
            apiJsonMap.put("currentThreadUserTime", ThreadMXBeanUtils.getCurrentThreadUserTime());
        }
        if (Boolean.TRUE.equals(ThreadMXBeanUtils.isThreadAllocatedMemoryEnabled())) {
            apiJsonMap.put("currentThreadAllocatedBytes", ThreadMXBeanUtils.getCurrentThreadAllocatedBytes());
        }
        return JsonUtils.toJson(apiJsonMap);
    }
}

第4步:使用

[2024-01-22 23:59:54.392_392] [WARN ] [http-nio-8080-exec-3] [LogFilter.java:21][LogFilter.doFilter: Start processing request at 2024-01-22T15:59:54.392746300Z - /students]
***LogFilter.doFilter.start***
***RequestHeaderCheckFilter.doFilter.start***

***ResponsePostInterceptor.preHandle***
***LogInterceptor.preHandle***
[2024-01-22 23:59:54.414_414] [WARN ] [http-nio-8080-exec-3] [LogInterceptor.java:36][LogInterceptor.postHandle: Start processing request at 2024-01-22T15:59:54.414364Z - /students]

***StudentController.edit***
[2024-01-22 23:59:56.589_589] [INFO ] [http-nio-8080-exec-3] [HikariDataSource.java:110][practisedb - Starting...]
[2024-01-22 23:59:56.730_730] [INFO ] [http-nio-8080-exec-3] [HikariPool.java:565][practisedb - Added connection com.mysql.cj.jdbc.ConnectionImpl@1e073db7]
[2024-01-22 23:59:56.732_732] [INFO ] [http-nio-8080-exec-3] [HikariDataSource.java:123][practisedb - Start completed.]

***ResponsePostAdvice.supports***
***ResponsePostAdvice.beforeBodyWrite***

***LogInterceptor.postHandle***
***ResponsePostInterceptor.postHandle***

***LogInterceptor.afterCompletion***
[2024-01-22 23:59:57.328_328] [WARN ] [http-nio-8080-exec-3] [LogInterceptor.java:56][LogInterceptor.postHandle: Finished processing request at 2024-01-22T15:59:57.328849300Z - /students in 2914 ms. Status code: 200]
[2024-01-22 23:59:57.715_715] [INFO ] [http-nio-8080-exec-3] [LogInterceptor.java:60][{"traceId":"5fef66027b0b45b1a509b7c1c4388b28","end_date":"2024-01-22T23:59:57.5332642+08:00[Asia/Shanghai]","cost":2914,"remoteHost":"0:0:0:0:0:0:0:1","remoteAddr":"0:0:0:0:0:0:0:1","remotePort":8263,"method":"PUT","requestURI":"/students","status":200,"requestContentLength":180,"sql_count":0,"currentThreadTime":109,"currentThreadUserTime":93,"currentThreadAllocatedBytes":29778776}]
[2024-01-22 23:59:57.715_715] [WARN ] [http-nio-8080-exec-3] [LogFilter.java:30][LogFilter.doFilter: Finished processing request at 2024-01-22T15:59:57.715645Z - /students in 3323 ms. Status code: 200]
***ResponsePostInterceptor.afterCompletion***

***RequestHeaderCheckFilter.doFilter.end***
***LogFilter.doFilter.end***

到了这里,关于SpringBoot 统计更多Api接口日志信息的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 域名 SSL 证书信息解析 API 数据接口

    域名 SSL 证书信息解析 API 数据接口 网络工具,提供域名 SSL 证书信息解析,多信息查询,毫秒级响应。 提供域名 SSL 证书信息解析; 最完整 SSL 属性信息解析; 支持多种元素信息抽取,包括主题的可辨识名称、颁发者的可辨识名称、序列号、有效起始日期、有效结束日期、

    2024年02月21日
    浏览(37)
  • 免费可用的企业工商信息API 接口推荐

    全国招投标查询 查询招标保标信息,涵盖招标信息查询、中标信息查询、VIP项目、拟在建项目、业主委托项目、PPP项目、项目来源、历史招标库、政府采集信息、招标定制、订阅推送、订阅导出、数据下载等数十个招投标领域。 工商详细信息查询 查询全国企业工商信息,根

    2024年02月09日
    浏览(39)
  • SpringBoot的日志信息及Lombok的常用注解

    日志是我们程序重要组成部分,它是程序在运行过程当中输出的一些提示或异常信息,我们可以通过日志来观察程序执行的情况,如果程序出现 Bug,我们可以根据日志去发现和排查程序的 Bug。 SpringBoot 项目在启动的时候,就会有默认的日志输出,如下图所示: 之所以会有上

    2024年02月12日
    浏览(35)
  • API接口:查询企业联系人邮箱及相关信息

    查询企业联系人邮箱API接口是一种非常实用的API接口,它可以帮助我们快速获取企业联系人的邮箱地址。这个接口可以在各种需要进行营销活动或者联系客户的场合中使用,例如邮件广告、市场调研等。 这篇博文将详细介绍这个API接口的原理和功能,并提供示例代码来演示如

    2024年02月08日
    浏览(53)
  • SpringBoot自定义starter之接口日志输出

    本文灵感来源是一道面试题。 要求做一个可以复用的接口日志输出工具,在使用时引入依赖,即可使用。 可能用在多个项目中。 问题处理思路是,自定义一个SpringBoot的Starter,可以加入一些功能配置。核心使用自定义注解、Aspect切面来做。 用切面去切你的自定义注解即可。

    2024年02月08日
    浏览(46)
  • 【Django学习】(十五)API接口文档平台_项目流程分析_日志器_认证_授权

    使用API接口文档不经可以很好的的维护接口数据,还给测试人员的接口测试工作带来了便利; 我们可以在全局配置文件中添加路由路径生成接口文档 1.1在全局配置文件里指定用于支持coreapi的Schema 1.2在全局路由表中添加路径   页面效果: 2.1 一定要先在配置表中注册drf_yas

    2024年02月15日
    浏览(61)
  • SpringBoot API 接口防刷

    接口防刷: 顾名思义,想让某个接口某个人在某段时间内只能请求N次。 在项目中比较常见的问题也有,那就是连点按钮导致请求多次,以前在web端有表单重复提交,可以通过token来解决。 除了上面的方法外,前后端配合的方法。现在全部由后端来控制。 在你请求的时候,服

    2023年04月18日
    浏览(39)
  • Springboot基于微信小程序的员工日志管理信息系统

    一、项目介绍 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作规则和开发

    2024年02月02日
    浏览(49)
  • 淘宝商品数据爬取商品信息采集数据分析API接口

         数据采集是数据可视化分析的第一步,也是最基础的一步,数据采集的数量和质量越高,后面分析的准确的也就越高,我们来看一下淘宝网的数据该如何爬取。 点此获取淘宝API测试key密钥 淘宝网站是一个动态加载的网站,我们之前可以采用解析接口或者用Selenium自动化

    2024年03月11日
    浏览(70)
  • 一键获取域名的相关信息——域名反查Api接口的神奇功能

    在现代互联网时代中,域名是我们上网必备的工具,它承载着我们上网所需的所有信息。但是有时我们需要了解域名的相关信息,比如IP地址、注册人信息、域名到期时间等等。这时候,我们就需要用到域名反查API接口,来获取这些信息。 一键获取域名的相关信息——域名反

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包