异常信息记录入库
方案介绍
将异常信息放在日志里面,如果磁盘定期清理,会导致很久之前的日志丢失,因此考虑将日志中的异常信息存在表里,方便后期查看定位问题。
由于项目是基于SpringBoot构架的,所以采用@AdviceController+@ExceptionHandler对全局异常进行拦截和处理,而后将异常信息通过异步任务的方式记录到数据库,之所以采用异步任务,是防止异常记录出现问题影响主流程:
方案实现
定义异常处理表
CREATE TABLE exception_log_t (id int(10) NOT NULL AUTO_INCREMENT COMMENT '主键id',msg varchar(1024) NOT NULL COMMENT '异常信息',stack_trace text DEFAULT NULL COMMENT '异常堆栈信息',create_by bigint(10) DEFAULT NULL COMMENT '创建人',creation_date datetime NOT NULL COMMENT '异常发生时间',PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='异常信息日志表';
GlobalExceptionHandler带有@ControllerAdvice和@ExceptionHandler注解,可以拦截异常并处理,同时组装异常记录信息给异步任务进行记录
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {/*** 处理自定义异常*/@ExceptionHandler(value = CommonException.class)@ResponseBodypublic BasicResponse bizExceptionHandler(CommonException e) {log.error("CommonException error info:", e);recordExceptionMsg(e);return BasicResponse.commonError(e);}/*** 处理其他异常*/@ExceptionHandler(value = Exception.class)@ResponseBodypublic BasicResponse exceptionHandler(Exception e) {log.error("Exception error info:", e);recordExceptionMsg(e);return BasicResponse.errorWithMsg(e.getMessage());}/*** 处理自定义异常*/@ExceptionHandler(value = IllegalStateException.class)@ResponseBodypublic BasicResponse IllegalStateExceptionHandler(IllegalStateException e) {log.error("IllegalStateException error info:", e);recordExceptionMsg(e);return BasicResponse.errorWithMsg(e.getMessage());}/*** 处理NoSuchAlgorithmException异常*/@ExceptionHandler(value = NoSuchAlgorithmException.class)@ResponseBodypublic BasicResponse NoSuchAlgorithmExceptionHandler(NoSuchAlgorithmException e) {log.error("NoSuchAlgorithmException error info:", e);recordExceptionMsg(e);return BasicResponse.errorWithMsg(e.getMessage());}/*** 组装异常记录信息*/private <T extends Exception> void recordExceptionMsg(T ex) {String exStackTrace = "";try {exStackTrace = getExStackTrace(ex);} catch (IOException e) {log.error("get exception stack track info error:", e);}String message = ex.getMessage();if (message.length() > 1024) {message = message.substring(0, 1024);}ExceptionMsgPo exceptionMsgPo = ExceptionMsgPo.builder().msg(message).stackTrace(exStackTrace).creationDate(new Date()).createBy(UserContext.getUserId()).build();AsyncRecordExceptionMsg asyncRecordExMsg = AppContextUtil.getBean(AsyncRecordExceptionMsg.class);// 调用异步任务入库asyncRecordExMsg.recordExceptionMsgTask(exceptionMsgPo);}private <T extends Exception> String getExStackTrace(T ex) throws IOException {//读取异常堆栈信息ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();ex.printStackTrace(new PrintStream(arrayOutputStream));//通过字节数组转换输入输出流BufferedReader fr = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(arrayOutputStream.toByteArray())));String str;StringBuilder exceptionSb = new StringBuilder();while ((str = fr.readLine()) != null) {exceptionSb.append(str);exceptionSb.append("\n");}return exceptionSb.toString();}
}
异步任务记录异常比较简单, 就调用IExceptionMsgMapper进行入库
@Component
@Slf4j
public class AsyncRecordExceptionMsg {@Autowiredprivate IExceptionMsgMapper exceptionMsgMapper;@Async("asyncPoolTaskExecutor")public void recordExceptionMsgTask(ExceptionMsgPo exceptionMsgPo){log.info("begin to do recordExceptionMsgTask");exceptionMsgMapper.insert(exceptionMsgPo);log.info("end of recordExceptionMsgTask");}
}
需要注意的是,@Async异步任务虽然方便,但是要注意控制线程数量,避免线程耗尽资源, @Async("asyncPoolTaskExecutor")中的asyncPoolTaskExecutor将线程池定义如下:
@Configuration
@EnableAsync
public class SyncConfiguration {@Bean(name = "asyncPoolTaskExecutor")public ThreadPoolTaskExecutor executor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();//核心线程数taskExecutor.setCorePoolSize(10);//线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程taskExecutor.setMaxPoolSize(100);//缓存队列taskExecutor.setQueueCapacity(50);//许的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁taskExecutor.setKeepAliveSeconds(200);//异步方法内部线程名称taskExecutor.setThreadNamePrefix("async-task-");/*** 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略* 通常有以下四种策略:* ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。* ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。* ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)* ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功*/taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());taskExecutor.initialize();return taskExecutor;}
}
ExceptionMsgPo定义
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("exception_log_t")
public class ExceptionMsgPo {@TableId(value="id",type = IdType.AUTO)private Long id;@TableField("msg")private String msg;@TableField("stack_trace")private String stackTrace;@TableField("create_by")protected Long createBy;@TableField("creation_date")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date creationDate;
}
测试效果
应用抛出异常,记录

相关文章:
异常信息记录入库
方案介绍 将异常信息放在日志里面,如果磁盘定期清理,会导致很久之前的日志丢失,因此考虑将日志中的异常信息存在表里,方便后期查看定位问题。 由于项目是基于SpringBoot构架的,所以采用AdviceControllerExceptionHand…...
Spring Batch 高级篇-分区步骤
目录 引言 概念 分区器 分区处理器 案例 转视频版 引言 接着上篇:Spring Batch 高级篇-并行步骤了解Spring Batch并行步骤后,接下来一起学习一下Spring Batch 高级功能-分区步骤 概念 分区:有划分,区分意思,在…...
ES数据迁移_snapshot(不需要安装其他软件)
参考文章: 三种常用的 Elasticsearch 数据迁移方案ES基于Snapshot(快照)的数据备份和还原CDH修改ElasticSearch配置文件不生效问题 目录1、更改老ES和新ES的config/elasticsearch.yml2、重启老ES,在老ES执行Postman中创建备份目录…...
【Vue3 第二十章】异步组件 代码分包 Suspense内置组件 顶层 await
异步组件 & 代码分包 & Suspense内置组件 & 顶层 await 一、概述 在大型项目中,我们可能需要拆分应用为更小的块,以减少主包的体积,并仅在需要时再从服务器加载相关组件。这时候就可以使用异步组件。 Vue 提供了 defineAsyncC…...
「媒体邀约」四川有哪些媒体,成都活动媒体邀约
传媒如春雨,润物细无声,四川省位于中国西南地区,是中国的一个省份。成都市是四川省的省会,成都市是中国西部地区的政治、经济、文化和交通中心,也是著名的旅游胜地。每年的文化交流活动很多,也有许多的大企…...
@Autowired和@Resource的区别
文章目录1. Autowired和Resource的区别2. 一个接口多个实现类的处理2.1 注入时候报错情况2.2 使用Primary注解处理2.3 使用Qualifer注解处理2.4 根据业务情况动态的决定注入哪个serviceImpl1. Autowired和Resource的区别 Aurowired是根据type来匹配;Resource可以根…...
Linux系列:glibc程序设计规范与内存管理思想
文章目录前言命名规范说明版式风格内存管理与智能指针关于UML前言 这是一个基于lightdm、glibc、gobject、gtk、qt、glibc、x11、wayland等多个高质量开源项目总结而来的规范。 glibc处于内核态与用户态的边界,承上启下,对用户的体验影响非常大。其在系…...
Redis 集群
文章目录一、集群简介二、Redis集群结构设计🍉2.1 数据存储设计🍉2.2 内部通信设计三、cluster 集群结构搭建🍓3-1 cluster配置 .conf🍓3-2 cluster 节点操作命令🍓3-3 redis-trib 命令🍓3-4 搭建 3主3从结…...
EF 框架的简介、发展历史;ORM框架概念
一、EF 框架简介EF 全称是 EntityFramework 。Entity Framework是ADO.NET 中的一套支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架。ORM框架(Object Relational Mapping) 翻译过来就是对象关系映射。如果不用ORM框架,我们一般这样…...
注解原理剖析与实战
一、注解及其原理 1.注解的基本概念 注解,可以看作是对 一个类/方法的一个扩展的模版,每个类/方法按照注解类中的规则,来为类/方法注解不同的参数,在用到的地方可以得到不同的类/方法中注解的各种参数与值。 从JDK5开始ÿ…...
《STL源码剖析》理解之将类成员函数和for_each等算法结合
类成员函数可以通过函数适配器(function adapters)包装成一个仿函数(重载了operator()的类),将其搭配于STL算法一起使用。#include <algorithm> #include <functional> #include <vector> #include <iostream>using namespace std;class In…...
如何构建应用标准化体系
标准化的过程实际上就是对运维对象的识别和建模过程。形成统一的对象模型后,各方在统一的认识下展开有效协作,然后针对不同的运维对象,再抽取出它们所对应的运维场景,接下来才是运维场景的自动化实现。 在标准化的过程中…...
【RabbitMQ笔记03】消息队列RabbitMQ七种模式之WorkQueues工作队列模式
这篇文章,主要介绍消息队列RabbitMQ七种模式之WorkQueues工作队列模式。 目录 一、工作队列模式 1.1、什么是Work Queues模式 1.2、工作队列模式的使用 (1)引入依赖 (2)编写生产者 (3)编写…...
认识html
1.html的特点先看一段简单的html代码<html><head></head><body>hello world</body> </html>如果将这段带有这段代码的.html文件拉进浏览器中,就会出现一个页面,内容就是hello world,如下图:由上面的代码,我们可以了解到一些html代码的特点…...
在外包公司熬了 3 年终于进了字节,竭尽全力....
其实两年前校招的时候就往字节投了一次简历,结果很明显凉了,随后这个理想就被暂时放下了,但是这个种子一直埋在心里这两年除了工作以外,也会坚持写博客,也因此结识了很多优秀的小伙伴,从他们身上学到了特别…...
绝对让你明明白白,脚把脚带你盯着 I2C 时序图将 I2C 程序给扣出来(基于STM32的模拟I2C)
目录前言一、关于STM32 I/O端口位的基本结构讲解二、模拟I2C编写前的需知道的知识1、I2C简介2、根据时序编写模拟I2C程序重要的两点Ⅰ、主机发送数据给从机时的时序控制Ⅱ、主机接收来自从机的数据时的时序控制Ⅲ、完整的I2C时序图(按写程序的思想分割时序ÿ…...
2023年全国最新工会考试精选真题及答案5
百分百题库提供工会考试试题、工会考试预测题、工会考试真题、工会证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、单选题 1.企业工会委员会实行(),重要问题须经(&#x…...
一文2000字手把手教你自动化测试Selenium+pytest+数据驱动
主流自动化框架 selenium :web端自动化框架 ,(行业里面最核心的框架) appium :手机app端框架 requests :接口测试 selenium 工具类封装 selenium提供了很多方法供我们去完成网页元素的操作, …...
windows安装Ubuntu子系统以及图形化界面记录
文章目录1. windows环境设置2. 开始安装3. ubuntu使用3.1 启动和退出 Linux 子系统3.2 安装位置3.3 更换源4. 安装图形化界面4.1 安装VcXsrv4.2 安装桌面环境(1)方法1:VcXsrv Gnome(2)方法2:VcXsrv Xfce4…...
通俗易懂,十分钟读懂DES,详解DES加密算法原理,DES攻击手段以及3DES原理。Python DES实现源码
文章目录1、什么是DES2、DES的基本概念3、DES的加密流程4、DES算法步骤详解4.1 初始置换(Initial Permutation,IP置换)4.2 加密轮次4.3 F轮函数4.3.1 拓展R到48位4.3.2 子密钥K的生成4.3.3 当前轮次的子密钥与拓展的48位R进行异或运算4.3.4 S盒替换(Subs…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
python读取SQLite表个并生成pdf文件
代码用于创建含50列的SQLite数据库并插入500行随机浮点数据,随后读取数据,通过ReportLab生成横向PDF表格,包含格式化(两位小数)及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...
STM32 低功耗设计全攻略:PWR 模块原理 + 睡眠 / 停止 / 待机模式实战(串口 + 红外 + RTC 应用全解析)
文章目录 PWRPWR(电源控制模块)核心功能 电源框图上电复位和掉电复位可编程电压监测器低功耗模式模式选择睡眠模式停止模式待机模式 修改主频一、准备工作二、修改主频的核心步骤:宏定义配置三、程序流程:时钟配置函数解析四、注意…...
