javascript
SpringBoot2 集成日志,复杂业务下的自定义实现
本文源碼:GitHub·點這里 || GitEE·點這里
一、日志體系集成
1、日志管理
在系統的開發中,最關鍵的一個組件工具就是日志,日志打印方便問題排查,或者生產事故回溯,日志記錄用來監控并分析系統性能點,并以此為依據,不斷對系統進行優化;同時基于用戶的操作日志,對用戶行為進行分析,開發智能推薦的功能,或者進行營銷投放,這在系統中都是常見且關鍵的業務流程。
2、ELK日志體系
在大型系統架構中,ELK的日志管理系統是系統必備功能,ELK-Stack是Elasticsearch、Logstash、Kiban三個開源軟件的組合,通常用來做日志分析,實時數據檢索。基于Logstash做數據流動通道,使日志數據不斷的流入搜索組件,基于Elasticsearch做數據實時查詢,基于Kiban的ES可視化界面,以此實現日志數據的搜集、存儲、分析等核心功能,且該體系方便擴展。
ELK相關文章:
- SpringBoot2整合ElasticSearch框架
- 搜索引擎框架,ElasticSearch集群模式
- 基于Logstash全量或增量同步數據到ES中間件
基于ELK體系的核心操作,有關于ElasticSearch其他文章可以自行查閱之前的內容,這里不在陳列,好像很多東西都是這樣一點點積累出來的。
二、集成環境
1、項目結構
defined-log-api:測試工程;
defined-log-config:日志核心模塊,依賴之后使用該模塊下注解即可;
2、數據表結構
CREATE TABLE dt_defined_log (id INT ( 11 ) NOT NULL AUTO_INCREMENT COMMENT '主鍵',class_name VARCHAR ( 200 ) DEFAULT NULL COMMENT '請求類名',method_name VARCHAR ( 100 ) DEFAULT NULL COMMENT '請求方法名',method_desc VARCHAR ( 100 ) DEFAULT NULL COMMENT '請求方法描述',api_type INT ( 1 ) DEFAULT 0 COMMENT 'API類型',biz_nature INT ( 1 ) DEFAULT 0 COMMENT '業務性質類型',data_flow_type INT ( 1 ) DEFAULT 0 COMMENT '日志數據流向',req_param VARCHAR ( 200 ) DEFAULT NULL COMMENT '請求報文',res_param VARCHAR ( 200 ) DEFAULT NULL COMMENT '響應報文',PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '日志記錄表';這里完全基于業務需求自定義即可。
三、核心代碼說明
1、注解參數
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface DefinedLog {/*** 操作類型*/ApiTypeEnum apiType () ;/*** 方法描述*/String methodDesc();/*** 業務性質*/BizNatureEnum bizNature() ;/*** 數據流向,與業務性質關聯*/DataFlowEnum dataFlow() ;/*** 存儲入參*/boolean isSaveReqParam () default true ;/*** 存儲出參*/boolean isSaveResParam() default true ;/*** 是否需要異步處理*/boolean isAsync () default false ; }這里描述一下如下幾個參數的意思:
bizNature:業務性質,即該日志是否有分析,或者營銷推廣操作,例如在在電商業務中,瀏覽系列商品后是否推送廣告;
dataFlow:數據流向,即數據存儲后是否向其他數據源推送,常見可能推送到MQ或者Redis或者分析引擎中,推薦類系統中對關鍵日志實時性要求極高,可以基于此做用戶行為實時分析;
isAsync:是否異步處理,在一些并發高的接口中,避免日志記錄成為性能問題的一個因素;
其他相關參數都是十分常見,例如接口類型增刪改查,入參出參報文存儲,方法模塊的描述等等,這些都可以基于業務的需求自定義,然后做相關業務處理開發,思路開闊即可。
2、切面攔截
基于切面編程是方式,做相關日志處理,獲取相應參數,構建日志模型即可。
@Component @Aspect public class LogAop {private static final Logger LOGGER = LoggerFactory.getLogger(LogAop.class);@Value("${spring.application.app-id}")private String appId ;@Resourceprivate DefineLogService defineLogService ;/*** 日志切入點*/@Pointcut("@annotation(com.defined.log.annotation.DefinedLog)")public void logPointCut() {}/*** 環繞切入*/@Around("logPointCut()")public Object around (ProceedingJoinPoint proceedingJoinPoint) throws Throwable {Object result = null ;StopWatch stopWatch = new StopWatch();stopWatch.start();try{// 執行方法result = proceedingJoinPoint.proceed();stopWatch.stop();} catch (Exception e){stopWatch.stop();} finally {// 保存日志LOGGER.info(" execute time: {} ms ", stopWatch.getTotalTimeMillis());DefineLogModel defineLogModel = buildLogParam (proceedingJoinPoint);defineLogModel.setResParam(JSONObject.toJSONString(result));defineLogService.saveLog(defineLogModel) ;}return result ;}private DefineLogModel buildLogParam (ProceedingJoinPoint point){DefineLogModel defineLogModel = new DefineLogModel() ;MethodSignature signature = (MethodSignature) point.getSignature();Method reqMethod = signature.getMethod();String className = point.getTarget().getClass().getName();Object[] reqParam = point.getArgs();LOGGER.info("請求方法:"+reqMethod.getName());LOGGER.info("請求類名:"+className);LOGGER.info("請求參數:"+ JSONObject.toJSONString(reqParam));// 獲取方法上注解reqMethod.getAnnotation(DefinedLog.class).getClass();DefinedLog definedLog = reqMethod.getAnnotation(DefinedLog.class);// 構建參數String methodName = reqMethod.getName() ;Integer apiType = definedLog.apiType().getApiType();String apiTypeDesc = definedLog.apiType().getApiTypeDesc();String methodDesc = definedLog.methodDesc() ;Integer bizNature = definedLog.bizNature().getBizNature() ;Integer dataFlowType = definedLog.dataFlow().getDataFlowType();boolean isSaveReqParam = definedLog.isSaveReqParam();boolean isSaveResParam = definedLog.isSaveResParam();boolean isAsync = definedLog.isAsync() ;defineLogModel.setAppId(appId);defineLogModel.setClassName(className);defineLogModel.setMethodName(methodName);defineLogModel.setMethodDesc(methodDesc);defineLogModel.setApiType(apiType);defineLogModel.setApiTypeDesc(apiTypeDesc);defineLogModel.setBizNature(bizNature);defineLogModel.setDataFlowType(dataFlowType);defineLogModel.setSaveReqParam(isSaveReqParam);defineLogModel.setSaveResParam(isSaveResParam);defineLogModel.setAsync(isAsync);defineLogModel.setReqParam(JSONObject.toJSONString(reqParam));return defineLogModel ;} }3、使用方式
DefinedLog注解在接口方法上即可。
@RestController public class LogController {@GetMapping("/logApi")@DefinedLog(apiType=ApiTypeEnum.COMPOSITE,methodDesc="測試日志",bizNature= BizNatureEnum.DEFAULT,dataFlow= DataFlowEnum.DEFAULT)public String logApi (@RequestParam("param") String param){return "success-re" ;}}4、記錄參數
這樣自定義日志流程就完成了。
四、源代碼地址
GitHub·地址 https://github.com/cicadasmile/middle-ware-parent GitEE·地址 https://gitee.com/cicadasmile/middle-ware-parent推薦閱讀:微服務架構系列
| 微服務架構:項目技術選型簡介,架構圖解說明 |
| 微服務架構:業務架構設計,系統分層管理 |
| 微服務架構:數據庫選型簡介,業務數據規劃設計 |
| 微服務架構:中間件集成,公共服務封裝 |
| 微服務架構:SpringCloud 基礎組件應用設計 |
| 微服務架構:通過業務、應用、技術、存儲,聊聊架構 |
| 微服務技術棧:常見注冊中心組件,對比分析 |
| 微服務技術棧:流量整形算法,服務熔斷與降級 |
| 微服務技術棧:API網關中心,落地實現方案 |
總結
以上是生活随笔為你收集整理的SpringBoot2 集成日志,复杂业务下的自定义实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: maven 热部署 web应用
- 下一篇: 发点去大唐芙蓉园的pp