spring web flux 记录用户日志及异常日志

package cn.finopen.boot.autoconfigure.aop;@Configuration
@EnableAspectJAutoProxy
@Order
public class EndpointLogAopConfiguration {/*** 请求方法白名单*/private static final String[] METHOD_WHITE_LIST = {"get", "unreadCount", "find", "findAll"};/*** 防止表单重复提交*/@Aspect@Service@Slf4jpublic static class EndpointLogAspect {@Pointcut("execution(* *.*.boot.autoconfigure..*.endpoint.*.*(..))")public void endpointPointcut() {}@Resourceprivate SaleGroupUserLogApiService logApiService;@Resourceprivate WechatService wechatService;@Resourceprivate StorageDataProperties properties;@Around("endpointPointcut()")public Object doAround(ProceedingJoinPoint pjp) throws Throwable {long start = System.currentTimeMillis();try {Object[] args = pjp.getArgs();Class<?> targetCls = pjp.getTarget().getClass();MethodSignature methodSignature = (MethodSignature) pjp.getSignature();String simpleName = targetCls.getSimpleName();String method = methodSignature.getName();if (method.startsWith("find")) {return proceed(pjp);}for (String i : METHOD_WHITE_LIST) {if (method.equals(i)) {return proceed(pjp);}}String targetObjectMethodName = simpleName + "." + method;String targetMethodParams = Arrays.toString(args);if (targetMethodParams.startsWith("[{") && targetMethodParams.endsWith("}]")) {JSONObject jsonObject;try {jsonObject = JSON.parseObject(targetMethodParams.substring(targetMethodParams.indexOf("{"), targetMethodParams.lastIndexOf("}") + 1));String loginUserId = jsonObject.getString("loginUserId");String loginGroupId = jsonObject.getString("loginGroupId");String loginGroupName = jsonObject.getString("loginGroupName");String requestIp = jsonObject.getString("requestIp");String body = JSONObject.toJSONString(jsonObject, SerializerFeature.WriteNullListAsEmpty);if (body.length() > 1024) {//内容过长截断body = body.substring(0, 1024);}if (loginGroupId != null && loginUserId != null) {logApiService.create(SaleGroupUserLogCreateReq.newBuilder().setLoginGroupId(Long.parseLong(loginGroupId)).setLoginUserId(loginUserId).setLoginGroupName(loginGroupName).setReqUrl(targetObjectMethodName).setReqIp(requestIp).setReqBody(body).build());}} catch (Exception ignore) {return proceed(pjp);}}return proceed(pjp);} catch (Throwable e) {throw print(e, pjp);} finally {long take = System.currentTimeMillis() - start;if (take >= 1000) {if (log.isWarnEnabled()) {log.warn("around endpoint [{}] take {}ms", pjp.getTarget().getClass().getSimpleName(), (System.currentTimeMillis() - start));}} else {if (log.isInfoEnabled()) {log.info("around endpoint [{}] take {}ms", pjp.getTarget().getClass().getSimpleName(), (System.currentTimeMillis() - start));}}}}/*** 为了捕获异步异常** @param pjp* @return* @throws Throwable*/private Object proceed(ProceedingJoinPoint pjp) throws Throwable {String url = properties.getUrl();
// 测试环境屏蔽boolean isTest = url.startsWith("https://test") || url.startsWith("http://test");Object result = pjp.proceed();if (isTest) {return result;}//这里是异步请求,所以直接用try cache 是无效的if (result instanceof Flux) {Flux<?> r = (Flux<?>) (result);return r.onErrorMap(Throwable.class, throwable -> print(throwable, pjp));} else if (result instanceof Mono) {Mono<?> r = (Mono<?>) (result);return r.onErrorMap(Throwable.class, throwable -> print(throwable, pjp));}return result;}private final static String WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=*";/*** 发送异常信息到企业微信** @param e* @param pjp*/private Throwable print(Throwable e, ProceedingJoinPoint pjp) {
//            if (e instanceof FibException) {
//                return e;
//            }ThreadPoolUtils.execute(() -> {Object[] args = pjp.getArgs();Class<?> targetCls = pjp.getTarget().getClass();MethodSignature methodSignature = (MethodSignature) pjp.getSignature();String simpleName = targetCls.getSimpleName();String method = methodSignature.getName();String targetObjectMethodName = simpleName + "." + method;String targetMethodParams = format(Arrays.toString(args));if (targetMethodParams.length() >= 512) {targetMethodParams = targetMethodParams.substring(0, 512);}String errorMessage = getStackTrace(e);String content = "<font color=\"info\">接口地址:</font>" + targetObjectMethodName + "\n<font color=\"info\">请求报文:</font>" + targetMethodParams + "\n<font color=\"warning\">异常消息:</font>" + errorMessage;//markdown内容,最长不超过4096个字节,必须是utf8编码if (content.length() >= 2048) {content = truncateUtf8(content);}WechatWebhookReq webhookReq = WechatWebhookReq.newBuilder().setUrl(WEBHOOK_URL).setMsgType("markdown").setContent(content).build();wechatService.send(webhookReq);});return e;}private String format(String targetMethodParams) {if (targetMethodParams.startsWith("[{") && targetMethodParams.endsWith("}]")) {try {JSONObject jsonObject = JSON.parseObject(targetMethodParams.substring(targetMethodParams.indexOf("{"), targetMethodParams.lastIndexOf("}") + 1));return JSONObject.toJSONString(jsonObject, SerializerFeature.WriteNullListAsEmpty);} catch (Exception ignore) {return targetMethodParams;}} else {return targetMethodParams;}}/**打印完整的日志信息**/String getStackTrace(Throwable e) {StringWriter sw = new StringWriter();PrintWriter pw = new PrintWriter(sw, true);// 打印当前异常的堆栈信息e.printStackTrace(pw);// 遍历并打印所有被抑制的异常(如果有)for (Throwable suppressed : e.getSuppressed()) {suppressed.printStackTrace(pw);}// 递归打印异常的原因链(如果存在)Throwable cause = e.getCause();while (cause != null) {cause.printStackTrace(pw);cause = cause.getCause();}return sw.toString();}/*** 截取UTF-8编码的字符串,确保字节长度不超过指定的最大值。** @param str 待截取的字符串* @return 截取后的字符串*/private final static int MARK_DOWN_MAX = 4096;/*** 简单地根据字节数截断UTF-8编码的字符串,可能会导致多字节字符被截断。** @param str 待截取的字符串* @return 截取后的字符串*/public static String truncateUtf8(String str) {byte[] bytes = str.getBytes(StandardCharsets.UTF_8);if (bytes.length <= MARK_DOWN_MAX) {return str;}// 直接截取到指定字节数对应的字符位置return new String(bytes, 0, MARK_DOWN_MAX, StandardCharsets.UTF_8);}}}

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

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

相关文章

MySQL8之mysql-community-common的作用

在MySQL 8中&#xff0c;mysql-community-common是一个软件包&#xff0c;它提供了MySQL服务器和客户端库所需的一些共同文件。具体来说&#xff0c;mysql-community-common的作用包括但不限于以下几点&#xff1a; 1. 提供基础配置和错误信息 错误信息和字符集包&#xff1a…

决策树算法简单介绍:原理和方案实施

决策树算法介绍&#xff1a;原理和方案实施 决策树&#xff08;Decision Tree&#xff09;是一种常用的机器学习算法&#xff0c;它既可以用于分类任务&#xff0c;也可以用于回归任务。由于其直观性和解释性&#xff0c;决策树在数据分析和模型构建中得到了广泛的应用。本文将…

如何防御DDoS攻击

如何防御DDoS攻击 1.硬件层面 使用高性能的防火墙 高性能的防火墙可以有效地过滤DDoS攻击流量&#xff0c;从而提高网络的抗攻击能力。企业可以使用性能强大的防火墙来防范DDoS攻击。 使用流量清洗设备 流量清洗设备可以实时监测网络流量&#xff0c;发现并过滤DDoS攻击流量&am…

顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

Spark操作Excel最佳实践

Spark操作Excel最佳实践 1、背景描述2、Apache POI与Spark-Excel2.1、Apache POI简介2.2、Spark-Excel简介3、Spark读取Excel3.1、导入依赖3.2、使用Apache POI3.3、使用Spark-Excel1、背景描述 数据开发中通常会涉及到Excel的处理。Java和Apache Spark都不支持读取Excel文件,…

挖K脚本检测指南

免责声明:本文仅做分享... 目录 挖K样本-Win&Linux-危害&定性 Linux-Web 安全漏洞导致挖K事件 Windows-系统口令爆破导致挖K事件 --怎么被挖K了??? 已经取得了权限. 挖K样本-Win&Linux-危害&定性 危害&#xff1a;CPU 拉满&#xff0c;网络阻塞&…

在Linux下使用Docker部署chirpstack

目录 一、前言 二、chirpstack 1、chirpstack是什么 2、chirpstack组件 3、为什么选择Docker部署 三、Linux下部署过程 四、web界面部署过程 一、前言 本篇文章我是在Linux下使用 Docker 进行部署chirpstack&#xff0c;chirpstack采用的是v4 版本&#xff0c;v4 版本 与…

Logstash常用的filter四大插件

以博客<ELK日志分析系统概述及部署>中实验结果为依据 补充&#xff1a;如何用正则表达式匹配一个ipv4地址 &#xff08;[0-9] | [1-9][0-9] | 1[0-9][0-9] | 2[04][0-9] | 25[0-5]&#xff09;\.&#xff08;[0-9] | [1-9][0-9] | 1[0-9][0-9] | 2[04][0-9] | 25[0-5]&a…

C++基础语法:嵌套类(内部类)

前言 "打牢基础,万事不愁" .C的基础语法的学习 引入 嵌套类的理解和使用 嵌套类(内部类)的特征 嵌套类是在类里面定义的类.class里嵌套另一个class,又称内部类(这种说法更形象) 1>内部类除了定义在外部类内部,和其他类没有太大区别.内部类对于外部类自动"可…

基于Java的数码论坛系统设计与实现

你好&#xff0c;我是计算机领域的研究者。如果你对数码论坛系统开发感兴趣或有相关需求&#xff0c;欢迎联系我。 开发语言&#xff1a; Java 数据库&#xff1a; MySQL 技术&#xff1a; Java技术、MySQL数据库、B/S架构、SpringBoot框架 工具&#xff1a; Eclipse、MySQ…

HJ41 称砝码下

接上文&#xff0c;HJ41 称砝码 更新acd代码&#xff0c;牛客代码如下 #include <stdio.h> #include <stdlib.h> #include <string.h>int calculateWeight(int *weight, int weightLen, int *num, int numLen) {int array[20001] {0};int hash[300001] {0…

css 文件重复类样式删除

上传文件 进行无关 className 删除 <div style"display: flex;"><input type"file" change"handleFileUpload" /><el-button click"removeStyles" :disabled"!fileContent">Remove Styles and Download&…

navigation运动规划学习笔记

DWA 动态窗口算法(Dynamic Window Approaches, DWA) 是基于预测控制理论的一种次优方法,因其在未知环境下能够安全、有效的避开障碍物, 同时具有计算量小, 反应迅速、可操作性强等特点。 DWA算法属于局部路径规划算法。 DWA算法的核心思想是根据移动机器人当前的位置状态和速…

antd a-select下拉框样式修改 vue3 亲测有效

记录一下遇到的问题 1.遇到问题&#xff1a; 使用到Vue3 Ant Design of Vue 3.2.20&#xff0c;但因为项目需求样式&#xff0c;各种查找资料都未能解决; 2.解决问题&#xff1a; ①我们审查元素可以看到&#xff0c;下拉框是在body中的; ①在a-select 元素上添加dropdownCla…

运行时异常与一般异常的异同

运行时异常与一般异常的异同 1、运行时异常&#xff08;Runtime Exception&#xff09;1.1 特点 2、 一般异常&#xff08;Checked Exception&#xff09;2.1 特点 3、异同点总结3.1 相同点3.2 不同点 4、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷…

【全网最全最详细】Tomcat 面试题大全

目录 一、说一说Tomcat的启动流程 二、Tomcat中有哪些类加载器? 三、为什么Tomcat可以把线程数设置为200,而不是N+1? 四、Tomcat处理请求的过程怎样的? 五、说一说Servlet的生命周期 六、过滤器和拦截器的区别? 七、介绍一下Tomcat的IO模型 八、说一说Tomcat的类加…

大语言模型系列-Transformer介绍

大语言模型系列&#xff1a;Transformer介绍 引言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Transformer模型已经成为了许多任务的标准方法。自从Vaswani等人在2017年提出Transformer以来&#xff0c;它已经彻底改变了NLP模型的设计。本文将介绍Transforme…

图形学各种二维基础变换,原来线性代数还能这么用,太牛了

缩放变换 均匀缩放 若想将一个图形缩小0.5倍 若x乘上缩放值s等于x撇&#xff0c;y同理&#xff0c;则 x ′ s x y ′ s y \begin{aligned} & x^{\prime}s x \\ & y^{\prime}s y \end{aligned} ​x′sxy′sy​&#xff0c;这样就表示了x缩小了s倍&#xff0c;y也是…

UML中用例之间的可视化表示

用例除了与参与者有关联关系外&#xff0c;用例之间也存在着一定的关系&#xff0c;如泛化关系、包含关系、扩展关系等。 4.2.1 包含关系 包含关系指的是两个用例之间的关系&#xff0c;其中一个用例&#xff08;称为基本用例&#xff0c;Base Use Case&#xff09;的行为包…

温度传感器的常见故障及处理方法

温度传感器作为现代工业、科研及日常生活中不可或缺的重要元件&#xff0c;其稳定性和准确性直接影响到设备的运行效率和安全。然而&#xff0c;由于各种因素的影响&#xff0c;温度传感器在使用过程中常会遇到一些故障。本文将针对这些常见故障进行分析&#xff0c;并提出相应…