关于springboot:SpringBoot2-集成日志复杂业务下的自定义实现

57次阅读

共计 4833 个字符,预计需要花费 13 分钟才能阅读完成。

本文源码: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 ;
    @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、应用形式

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 网关核心,落地实现计划

正文完
 0