住房和城乡建设部网站买卖合同,门户网站建设情况总结,泉州开发网站的公司有哪些,做网站 哪里发布方案介绍
将异常信息放在日志里面#xff0c;如果磁盘定期清理#xff0c;会导致很久之前的日志丢失#xff0c;因此考虑将日志中的异常信息存在表里#xff0c;方便后期查看定位问题。 由于项目是基于SpringBoot构架的#xff0c;所以采用AdviceControllerExceptionHand…方案介绍
将异常信息放在日志里面如果磁盘定期清理会导致很久之前的日志丢失因此考虑将日志中的异常信息存在表里方便后期查看定位问题。 由于项目是基于SpringBoot构架的所以采用AdviceControllerExceptionHandler对全局异常进行拦截和处理而后将异常信息通过异步任务的方式记录到数据库之所以采用异步任务是防止异常记录出现问题影响主流程
#mermaid-svg-K6HzXclI6Bt9Hbaf {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .error-icon{fill:#552222;}#mermaid-svg-K6HzXclI6Bt9Hbaf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-K6HzXclI6Bt9Hbaf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .marker.cross{stroke:#333333;}#mermaid-svg-K6HzXclI6Bt9Hbaf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-K6HzXclI6Bt9Hbaf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .cluster-label text{fill:#333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .cluster-label span{color:#333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .label text,#mermaid-svg-K6HzXclI6Bt9Hbaf span{fill:#333;color:#333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .node rect,#mermaid-svg-K6HzXclI6Bt9Hbaf .node circle,#mermaid-svg-K6HzXclI6Bt9Hbaf .node ellipse,#mermaid-svg-K6HzXclI6Bt9Hbaf .node polygon,#mermaid-svg-K6HzXclI6Bt9Hbaf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-K6HzXclI6Bt9Hbaf .node .label{text-align:center;}#mermaid-svg-K6HzXclI6Bt9Hbaf .node.clickable{cursor:pointer;}#mermaid-svg-K6HzXclI6Bt9Hbaf .arrowheadPath{fill:#333333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-K6HzXclI6Bt9Hbaf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-K6HzXclI6Bt9Hbaf .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-K6HzXclI6Bt9Hbaf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-K6HzXclI6Bt9Hbaf .cluster text{fill:#333;}#mermaid-svg-K6HzXclI6Bt9Hbaf .cluster span{color:#333;}#mermaid-svg-K6HzXclI6Bt9Hbaf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-K6HzXclI6Bt9Hbaf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}AdviceControllerExceptionHandler拦截发生异常处理异常返回信息异步记录异常堆栈信息结束方案实现
定义异常处理表
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)
) ENGINEInnoDB DEFAULT CHARSETutf8 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(valueid,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;
}测试效果
应用抛出异常记录