老生常談SpringAop日志收集與處理做的工具包


AopLog是基於Spring Aop 和ThreadLocal實現的一個專門對請求方法內容日志的攔截與處理的日志工具包。

場景 :

  1. 使用Spring Aop攔截參數日志目前大部分做法都基本上大同小異,不想日后每個項目工程都寫一份這樣的Aop攔截處理日志的代碼,甚至代碼侵入。
  2. 我想知道一些相對重要的請求方法的請求參數,響應參數,請求頭,以及內部耗時,方法是成功還是失敗等等信息。發生錯誤時我也不知道執行到哪一步發生了異常,是不是某個參數導致出的邏輯問題。
  3. 普通的log.info或warn信息沒有所屬請求的上下關系,並不方便查看和分析。
  4. 正式環境中,我並不想打印太多無意義的info日志(有些只是為了排查問題打印的日志,程序正常運行時其實毫無意義),只希望在發生異常時記錄日志或者只希望每次請求只記錄一條關鍵的請求信息。
  5. 日志的收集,我希望將這些請求的日志記錄下來,記錄的實現方式我自己決定,比如正常的日志打印,常見的日志寫入數據庫,日志寫入到文件,日志入隊列等等。
  6. 整個日志的記錄完全不干擾正常請求方法的流程,日志的收集處理異步化,完全不影響正常請求方法的性能與響應。
  7. 只需要通過@AopLog注解決定是否記錄。

快速開始

項目通過maven的pom.xml引入


<dependency>
    <groupId>com.github.ealenxie</groupId>
    <artifactId>aop-log</artifactId>
    <version>2.4</version>
</dependency>

或者通過gradle引入


compile group: 'com.github.ealenxie', name: 'aop-log', version: '2.4'

@AopLog注解使用,進行日志記錄

直接在類(作用類的所有方法)或類方法(作用於方法)上加上注解@AopLog,進行日志記錄

例如 :

import com.github.AopLog;
import name.ealen.infra.base.resp.RespBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author EalenXie create on 2020/6/22 14:28
 */
@AopLog(type = "測試",stackTraceOnErr = true)
@RestController
public class AppController {

    @GetMapping("/app/sayHello")
    public RespBody<String> sayHello() {
        return RespBody.ok("hello EalenXie");
    }

}

自定義全局的日志收集器實現收集 LogCollector

例如只是簡單打印,或寫入到庫等等。


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.LogData;
import com.github.collector.LogCollector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author EalenXie create on 2020/9/15 13:46
 * 此為樣例參考
 * 配置一個簡單的日志收集器 這里只是做了一個log.info打印一下,可以在這里寫入到數據庫中或者寫入
 */
@Slf4j
@Component
public class AopLogCollector implements LogCollector {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public void collect(LogData logData) {
        try {
            log.info(objectMapper.writeValueAsString(logData));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

配置@Component的全局日志收集器只能配置一個。

接口調用 /say/hello 測試即可看看到控制台打印出結果 :

2020-09-16 16:01:04.782  INFO 2012 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"測試","content":"","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"請求成功","dateTime":"2020-09-16 16:01:04","body":"hello EalenXie"},"logDate":1600243264780,"costTime":1,"threadName":"http-nio-8080-exec-3","threadId":33,"success":true}

記錄的日志對象LogData屬性說明

LogData 記錄的內容

字段 類型 注釋
appName String 應用名稱
host String 主機
port int 端口號
clientIp String 請求客戶端的Ip
reqUrl String 請求地址
headers Object 請求頭部信息(可選擇記錄) 默認記錄user-agent,content-type
type String 操作類型,默認值undefined
content String 方法步驟內容,默認是空,可使用LogData.step進行內容步驟記錄
method String 請求的本地java方法
args Object 方法請求參數
respBody Object 方法響應參數
costTime long 整個方法耗時
logDate Date Log產生時間,LogData對象初始化的時間
threadName String 線程名稱
threadId long 線程Id
success boolean 執行狀態,成功(true)/異常(false)

AopLog 注解選項說明

選項 類型 說明 默認
logOnErr boolean 僅當發生異常時才記錄收集 false
type String 操作類型 默認值"undefined"
headers String[] 記錄的header信息 ,選擇要記錄哪些header信息 默認"User-Agent","content-type"
args boolean 是否記錄請求參數 true
respBody boolean 是否記錄響應參數 true
stackTraceOnErr boolean 當目標方法發生異常時,是否追加異常堆棧信息到LogData的content中 false
asyncMode boolean 異步方式收集 true
collector Class<? extends LogCollector> 指定日志收集器 默認不調整收集器,使用全局的日志收集器

LogData的step方法。

記錄步驟。(如果某些重要步驟希望被記錄下來)
例如 :

import com.github.AopLog;
import com.github.LogData;
import name.ealen.infra.base.resp.RespBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * @author EalenXie create on 2020/6/22 14:28
 */
@AopLog(type = "測試",stackTraceOnErr = true)
@RestController
public class AppController {


    @GetMapping("/app/sayHello")
    public RespBody<String> sayHello() {
        LogData.step("1. 第一步執行完成");
        //......
        LogData.step("2. 第二步執行完成");
        //.....
        LogData.step("3. service的方法執行完成");
        //.....
        return RespBody.ok("hello EalenXie");
    }

}

此時再次接口調用 /say/hello 測試即可看看到控制台打印出結果,重點觀察content字段 :

2020-09-16 17:26:20.285  INFO 3284 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"測試","content":"1. 第一步執行完成\n2. 第二步執行完成\n3. service的方法執行完成\n","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"請求成功","dateTime":"2020-09-16 17:26:20","body":"hello EalenXie"},"logDate":1600248380283,"costTime":1,"threadName":"http-nio-8080-exec-2","threadId":32,"success":true}

關於

開源Github地址 : https://github.com/EalenXie/aop-log

感謝各位提出意見和支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM