溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SpringBoot2集成日志以及復(fù)雜業(yè)務(wù)下的自定義實(shí)現(xiàn)是怎樣的

發(fā)布時(shí)間:2021-11-15 15:56:35 來(lái)源:億速云 閱讀:141 作者:柒染 欄目:大數(shù)據(jù)

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)SpringBoot2集成日志以及復(fù)雜業(yè)務(wù)下的自定義實(shí)現(xiàn)是怎樣的,文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

一、日志體系集成

1、日志管理

在系統(tǒng)的開(kāi)發(fā)中,最關(guān)鍵的一個(gè)組件工具就是日志,日志打印方便問(wèn)題排查,或者生產(chǎn)事故回溯,日志記錄用來(lái)監(jiān)控并分析系統(tǒng)性能點(diǎn),并以此為依據(jù),不斷對(duì)系統(tǒng)進(jìn)行優(yōu)化;同時(shí)基于用戶的操作日志,對(duì)用戶行為進(jìn)行分析,開(kāi)發(fā)智能推薦的功能,或者進(jìn)行營(yíng)銷(xiāo)投放,這在系統(tǒng)中都是常見(jiàn)且關(guān)鍵的業(yè)務(wù)流程。

2、ELK日志體系

在大型系統(tǒng)架構(gòu)中,ELK的日志管理系統(tǒng)是系統(tǒng)必備功能,ELK-Stack是Elasticsearch、Logstash、Kiban三個(gè)開(kāi)源軟件的組合,通常用來(lái)做日志分析,實(shí)時(shí)數(shù)據(jù)檢索?;贚ogstash做數(shù)據(jù)流動(dòng)通道,使日志數(shù)據(jù)不斷的流入搜索組件,基于Elasticsearch做數(shù)據(jù)實(shí)時(shí)查詢,基于Kiban的ES可視化界面,以此實(shí)現(xiàn)日志數(shù)據(jù)的搜集、存儲(chǔ)、分析等核心功能,且該體系方便擴(kuò)展。

基于ELK體系的核心操作,有關(guān)于ElasticSearch其他文章可以自行查閱之前的內(nèi)容,這里不在陳列,好像很多東西都是這樣一點(diǎn)點(diǎn)積累出來(lái)的。

二、集成環(huán)境

1、項(xiàng)目結(jié)構(gòu)

SpringBoot2集成日志以及復(fù)雜業(yè)務(wù)下的自定義實(shí)現(xiàn)是怎樣的

defined-log-api:測(cè)試工程;

defined-log-config:日志核心模塊,依賴之后使用該模塊下注解即可;

2、數(shù)據(jù)表結(jié)構(gòu)

CREATE TABLE dt_defined_log (
	id INT ( 11 ) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
	class_name VARCHAR ( 200 ) DEFAULT NULL COMMENT '請(qǐng)求類(lèi)名',
	method_name VARCHAR ( 100 ) DEFAULT NULL COMMENT '請(qǐng)求方法名',
	method_desc VARCHAR ( 100 ) DEFAULT NULL COMMENT '請(qǐng)求方法描述',
	api_type INT ( 1 ) DEFAULT 0 COMMENT 'API類(lèi)型',
	biz_nature INT ( 1 ) DEFAULT 0 COMMENT '業(yè)務(wù)性質(zhì)類(lèi)型',
	data_flow_type INT ( 1 ) DEFAULT 0 COMMENT '日志數(shù)據(jù)流向',
	req_param VARCHAR ( 200 ) DEFAULT NULL COMMENT '請(qǐng)求報(bào)文',
	res_param VARCHAR ( 200 ) DEFAULT NULL COMMENT '響應(yīng)報(bào)文',
	PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '日志記錄表';

這里完全基于業(yè)務(wù)需求自定義即可。

三、核心代碼說(shuō)明

1、注解參數(shù)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DefinedLog {

    /**
     * 操作類(lèi)型
     */
    ApiTypeEnum apiType () ;

    /**
     * 方法描述
     */
    String methodDesc();

    /**
     * 業(yè)務(wù)性質(zhì)
     */
    BizNatureEnum bizNature() ;

    /**
     * 數(shù)據(jù)流向,與業(yè)務(wù)性質(zhì)關(guān)聯(lián)
     */
    DataFlowEnum dataFlow() ;

    /**
     * 存儲(chǔ)入?yún)?
     */
    boolean isSaveReqParam () default true ;

    /**
     * 存儲(chǔ)出參
     */
    boolean isSaveResParam() default true ;

    /**
     * 是否需要異步處理
     */
    boolean isAsync () default false ;
}

這里描述一下如下幾個(gè)參數(shù)的意思:

bizNature:業(yè)務(wù)性質(zhì),即該日志是否有分析,或者營(yíng)銷(xiāo)推廣操作,例如在在電商業(yè)務(wù)中,瀏覽系列商品后是否推送廣告;

dataFlow:數(shù)據(jù)流向,即數(shù)據(jù)存儲(chǔ)后是否向其他數(shù)據(jù)源推送,常見(jiàn)可能推送到MQ或者Redis或者分析引擎中,推薦類(lèi)系統(tǒng)中對(duì)關(guān)鍵日志實(shí)時(shí)性要求極高,可以基于此做用戶行為實(shí)時(shí)分析;

isAsync:是否異步處理,在一些并發(fā)高的接口中,避免日志記錄成為性能問(wèn)題的一個(gè)因素;

其他相關(guān)參數(shù)都是十分常見(jiàn),例如接口類(lèi)型增刪改查,入?yún)⒊鰠?bào)文存儲(chǔ),方法模塊的描述等等,這些都可以基于業(yè)務(wù)的需求自定義,然后做相關(guān)業(yè)務(wù)處理開(kāi)發(fā),思路開(kāi)闊即可。

2、切面攔截

基于切面編程是方式,做相關(guān)日志處理,獲取相應(yīng)參數(shù),構(gòu)建日志模型即可。

@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 ;

    /**
     * 日志切入點(diǎn)
     */
    @Pointcut("@annotation(com.defined.log.annotation.DefinedLog)")
    public void logPointCut() {

    }

    /**
     * 環(huán)繞切入
     */
    @Around("logPointCut()")
    public Object around (ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null ;
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try{
            // 執(zhí)行方法
            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("請(qǐng)求方法:"+reqMethod.getName());
        LOGGER.info("請(qǐng)求類(lèi)名:"+className);
        LOGGER.info("請(qǐng)求參數(shù):"+ JSONObject.toJSONString(reqParam));
        // 獲取方法上注解
        reqMethod.getAnnotation(DefinedLog.class).getClass();
        DefinedLog definedLog = reqMethod.getAnnotation(DefinedLog.class);

        // 構(gòu)建參數(shù)
        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="測(cè)試日志",
                bizNature= BizNatureEnum.DEFAULT,
                dataFlow= DataFlowEnum.DEFAULT)
    public String logApi (@RequestParam("param") String param){
        return "success-re" ;
    }

}

4、記錄參數(shù)

SpringBoot2集成日志以及復(fù)雜業(yè)務(wù)下的自定義實(shí)現(xiàn)是怎樣的

這樣自定義日志流程就完成了。

上述就是小編為大家分享的SpringBoot2集成日志以及復(fù)雜業(yè)務(wù)下的自定義實(shí)現(xiàn)是怎樣的了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI