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.pswp.cn/web/42287.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42287.shtml
英文地址,請注明出處:http://en.pswp.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;并提出相應…