SpringBoot2|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、项目结构 SpringBoot2|SpringBoot2 集成日志,复杂业务下的自定义实现
文章图片
26-1.png 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 ; @Resource private 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、使用方式 【SpringBoot2|SpringBoot2 集成日志,复杂业务下的自定义实现】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、记录参数 SpringBoot2|SpringBoot2 集成日志,复杂业务下的自定义实现
文章图片
26-2.png 这样自定义日志流程就完成了。
四、源代码地址
GitHub·地址 https://github.com/cicadasmile/middle-ware-parent GitEE·地址 https://gitee.com/cicadasmile/middle-ware-parent

推荐阅读:微服务架构系列
标题
微服务架构:项目技术选型简介,架构图解说明
微服务架构:业务架构设计,系统分层管理
微服务架构:数据库选型简介,业务数据规划设计
微服务架构:中间件集成,公共服务封装
微服务架构:SpringCloud 基础组件应用设计
微服务架构:通过业务、应用、技术、存储,聊聊架构
微服务技术栈:常见注册中心组件,对比分析
微服务技术栈:流量整形算法,服务熔断与降级
微服务技术栈:API网关中心,落地实现方案

    推荐阅读