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 {@Overridepublic 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;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {System.err.println("***LogInterceptor.postHandle***");// 获取请求开始时间}@Overridepublic 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使用统计

配置文件可以配置是否开启统计

thread:cpu_time_enabled: trueallocated_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;@Overridepublic 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***

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/640982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode27】 移除元素

27. 移除元素 快慢型双指针 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不…

vulhub之redis篇

CVE-2022-0543 | redis的远程代码执行漏洞 简介 CVE-2022-0543 该 Redis 沙盒逃逸漏洞影响 Debian 系的 Linux 发行版本,并非 Redis 本身漏洞, 漏洞形成原因在于系统补丁加载了一些redis源码注释了的代码 原理分析 redis一直有一个攻击面,就是在用户连接redis后,可以通过ev…

企业微信开发:本地运行一个页面应用

问题 在开发环境本地运行一个页面应用&#xff0c;将网页URL配置到企业微信的应用主页网址中&#xff0c;此时应用在企业微信中能够正常打开网页吗&#xff1f; 结论是&#xff1a;能够正常访问页面。 能够访问的前提 能够访问的前提条件&#xff0c;企业微信客户端所在的网…

界面控件DevExpress ASP.NET Data Grid组件 - 可快速处理各类型数据!(一)

由DevExpress开发的快速且功能完整的ASP.NET Web Forms的Data Grid组件&#xff0c;从全面的数据塑造和数据过滤选项到十多个集成数据编辑器&#xff0c;该套件提供了帮助用户构建极佳数据所需的一些&#xff0c;没有限制&#xff01; P.S&#xff1a;DevExpress ASP.NET Web …

k8s--helm

什么是helm&#xff1f;在没有这个helm之前&#xff0c;deployment service ingress helm的作用 通过打包的方式&#xff0c;把deployment service ingress等打包在一块&#xff0c;一键式的部署服务&#xff0c;类似yum安装 官方提供的一个类似与安装仓库额功能&#xff0c;…

Linux C语言开发(十)vim基本操作

目录 一.什么是vim 二.vim的进入与退出 三.vim的基本模式 四.vim的命令行模式操作

SPA vs MPA vs PWA

1、单页面应用程序&#xff08;SPA&#xff09; ① 什么是 SPA SPA 全称为 Single-Page Application&#xff0c;表示单页面应用程序。 也就是说只有一个 HTML 文件的 Web 应用&#xff0c;我们通过 Vue 开发的项目其实就是典型的 SPA应用 在单页面应用程序中&#xff0c;我…

C语言——结构体讲解

目录 一、结构体类型的声明 二、结构体变量的定义和初始化 三、结构体的重命名 四、结构体的自引用 五、结构体内存对齐 六、结构体传参 七、结构体实现位段 7.1 什么是位段 7.2 位段的声明和使用 7.3 位段的空间大小计算 7.4 位段的内存分配 7.5 位段的跨平…

计算机网络-物理层基本概念(接口特性 相关概念)

文章目录 总览物理层接口特性星火模型给出的相关概念解释&#xff08;仅供参考&#xff09; 总览 求极限传输速率&#xff1a;奈氏准则&#xff0c;香农定理&#xff08;背景环境不一样&#xff09; 编码&#xff1a;数据变成数字信号 调制&#xff1a;数字信号变成模拟信号 信…

Elasticsearch:2023 年 Lucene 领域发生了什么?

作者&#xff1a;来自 Elastic Adrien Grand 2023 年刚刚结束&#xff0c;又是 Apache Lucene 开发活跃的一年。 让我们花点时间回顾一下去年的亮点。 社区 2023 年&#xff0c;有&#xff1a; 5 个次要版本&#xff08;9.5、9.6、9.7、9.8 和 9.9&#xff09;&#xff0c;1 …

51单片机LED点阵屏

LED点阵屏 LED点阵屏是一种由许多小型LED灯组成的矩阵式显示屏。这些LED灯可以是单色、双色或全彩的&#xff0c;它们排列成行和列的网格&#xff0c;可以根据需要点亮来显示图像、文字或动画等内容。LED点阵屏广泛应用于户外广告牌、室内显示、交通信号灯、电子价格标签和其他…

【设计模式】字节三面:请举例阐释访问者模式

今天我们要一起探讨的主题是一种设计模式——访问者模式(Visitor Pattern)。我将从最基础的概念、应用场景&#xff0c;再到实例代码的展示&#xff0c;全方位的为大家剖析访问者模式。而且&#xff0c;我保证&#xff0c;你即使是编程新手&#xff0c;也能理解并开始应用这个设…

如何在 Ubuntu 22.04 上安装 Linux、Apache、MySQL、PHP (LAMP) 堆栈

前些天发现了一个人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;最重要的屌图甚多&#xff0c;忍不住分享一下给大家。点击跳转到网站。 如何在 Ubuntu 22.04 上安装 Linux、Apache、MySQL、PHP (LAMP) 堆栈 介绍 “LAMP”堆栈是一组开源软件&#…

uniapp 在static/index.html中添加全局样式

前言 略 在static/index.html中添加全局样式 <style>div {background-color: #ccc;} </style>static/index.html源码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"utf-8"><meta http-…

HCIA——21C/S、P2P、peer的选择

学习目标&#xff1a; 计算机网络 1.掌握计算机网络的基本概念、基本原理和基本方法。 2.掌握计算机网络的体系结构和典型网络协议&#xff0c;了解典型网络设备的组成和特点&#xff0c;理解典型网络设备的工作原理。 3.能够运用计算机网络的基本概念、基本原理和基本方法进行…

安全通信网络

1.网络架构 1&#xff09;应保证网络设备的业务处理能力满足业务高峰期需要。 设备CPU和内存使用率的峰值不大于设备处理能力的70%。 在有监控环境的条件下&#xff0c;应通过监控平台查看主要设备在业务高峰期的资源&#xff08;CPU、内存等&#xff09;使用 情况&#xff…

ES已有mapping下,新增字段且设置初始值

开发过程中随着业务的发展&#xff0c;内容累计&#xff0c;中途需要添加新的字段&#xff0c;并且设置初始值。 # 先查询原来的mapping GET test_index/_mapping # 新增字段 PUT test_index/_mapping {"properties": {"name": {"type": "…

【笔记】Disable APN 禁用数据连接的逻辑(Android KaiOS)

简介 通过OTA/OMADM 运营商服务器可以下发消息实现disable APN&#xff0c;从而影响Data PDN建立。APN被disable了会导致无法正常上网。 在Android 和 KaiOS 系统实现上有区别&#xff0c;不过都是通过carrier_enabled 这类字段实现判断控制。 Android&#xff1a;上层 Tele…

【Emotion】 自动驾驶最近面试总结与反思

outline 写在前面面试问题回顾和答案展望 写在前面 最近由于公司部门即将撤销&#xff0c;开始了新一轮准备。 发现现在整体行情不太乐观&#xff0c;很看过去的尤其是量产的经验 同时本次面试我coding环节答得不好&#xff0c;&#xff08;其实也是半年前大家问的比较简单…

fbx格式转换

目录 fbx转bvh bvh转fbx npz转换为fbx npz转换为fbx代码&#xff1a; convert2fbx.py fbx转bvh https://github.com/SinMDM/SinMDM/blob/0296efba20ae5875b6f1c092d277ea274e8ceda2/utils/fbx2bvh.py """ This code is a variation of https://github.co…