作者:lipengxs
鏈接:my.oschina.net/lipengxs/blog/3156247
背景
日志內容復雜多樣,如何去收集有價值的日志是我們重點關注的。日志的價值其實是取決於業務操作的,不同的業務場景下相同類型的日志的價值會截然不同。
根據以往的業務實踐,結合企業級的一些業務需求,我們選定關注以下幾類日志。
-
跟蹤日志【trace.log】 Server引擎的調試日志,用於系統維護人員定位系統運行問題使用。
-
系統日志【system.log】 大粒度的引擎運行的入口、出口的日志,用於調用棧分析,可以進行性能分析使用。
-
部署日志【deploy.log】 記錄系統啟動、停止、構件包部署、集群通知等信息的日志。
-
引擎日志【engine.log】 細粒度的引擎運行日志,可以打印上下文數據,用於定位業務問題。
-
構件包日志【contribution.log】 構件包記錄的業務日志(使用基礎構件庫的日志輸出API寫日志)
這里我們專門針對系統日志收集討論幾種收集方案,關注微信公眾號Java技術棧,在后台回復:微服務,可以獲取我整理的 N 篇 微服務系列教程,都是干貨。
方案一:通過日志組件來收集
這里是指通過logback、log4j等日志組件來輸出文件,然后再通過文件輸出到logstash、kibana等日志組件中,通過這些日志組件來進行可視化統計與分析,這里需要統一關鍵日志輸出格式方便日后統計搜索。
優點
-
操作簡單,收集方便
-
減少業務依賴
-
粒度細
缺點
-
依賴於logstash、kibana
-
只能滿足簡單的日志操作,詳細點或者個性化需求操作起來比較復雜
方案二:使用aop來攔截controller
攔截controller層,通過controller中的方法名是否包含insert、update、delete等關鍵字來記錄業務日志。
優點
- 操作簡單,收集方便
缺點
-
只能記錄簡單日志
-
不同的人命名習慣不一樣,日志可能不准確
方案三:使用注解來,進行稍微精准的業務日志記錄
這個方案粒度可大可小,代碼侵入性也比較小,可操作性比較強,如果需要獲取參數信息或者返回值信息,可以通過注解配置獲取到,可以集合fastjson中的jpath來獲取參數值下面有幾個偽代碼供參考
@Slf4j
@Aspect
public class SysLogAspect {
@Around("@annotation(sysLog)")
@SneakyThrows
public Object around(ProceedingJoinPoint point, SysLog sysLog) {
// 根據系統上下文獲取相關數據
Operation logVo = SysLogUtils.getOperationModel();
Object obj=null;
try{
// 操作方式
logVo.setOperationName(sysLog.value());
// 操作時間
logVo.setOperationTime(new Date());
logVo.setObjectType(sysLog.objectType().name());
logVo.setAppName(StringUtils.defaultString(sysLog.appName(),"TSP"));
// 發送異步日志事件
obj = point.proceed();
if(StringUtils.isNotBlank(sysLog.objectIdKey())&&StringUtils.isNotBlank(sysLog.objectNameKey())){
Map<String,Object> params=Maps.newHashMap();
params.put("args",point.getArgs());
params.put("response",obj);
logVo.setObjectId(getKeyValue(sysLog.objectIdKey(),params));
logVo.setObjectName(getKeyValue(sysLog.objectNameKey(),params));
}
}catch (BusinessException e){
logVo.setException(e.getMessage());
throw new Exception(e);
}catch (RuntimeException e){
logVo.setException(e.getMessage());
throw new Exception(e);
}catch (Exception e){
logVo.setException(e.getMessage());
throw new Exception(e);
}finally {
ApplicationContextUtils.publishEvent(new OperationEvent(logVo));
}
return obj;
}
private String getKeyValue(String key,Map<String,Object> params){
try{
Object mm= JSONPath.eval(params,key);
if(mm!=null){
return mm.toString();
}
}catch (Exception e){
log.error("JSONPath.eval:",e);
}
return null;
}
}
@SysLog(value = "xxxxxx",objectType = LogObjectType.OFFLINE_THRONG,
objectIdKey = "$['args'][0][0]['id']",objectNameKey = "$['response'][0][0]['throngName']")
優點
-
操作簡單
-
較靈活,粒度可大可小
缺點
-
有代碼侵入
-
個性化需求不滿足
方案四:針對復雜場景或者審計需求手動記錄,侵入性強
如果有些業務共用了方法,需要更小的粒度,或者需要記錄業務數據變更記錄,這時就只能選擇侵入式較強的方式來記錄日志了,直接在業務代碼中記錄日志,日志系統新貴 Loki,這個推薦看下。
logClient.logObject(LogObjectType.XXX,id,UserContext.getUserName(),"編輯xxx","xxx變更為xxxxx");
方案五:記錄sql日志
則可以使用mybatis攔截器來進行,如果沒有使用mybatis,則可以做一個通用的preparestatement以及statement代理。
當然現在已經有很對監控組件可以滿足這個需求,比如說jeager、javamelody、druid等。
總結
一般情況下我們會采用多種方式來記錄業務日志,這個都是根據具體需求來進行評估用哪幾種方式可以更好的達到產品需求。
近期熱文推薦:
1.Java 15 正式發布, 14 個新特性,刷新你的認知!!
2.終於靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!
3.我用 Java 8 寫了一段邏輯,同事直呼看不懂,你試試看。。
覺得不錯,別忘了隨手點贊+轉發哦!