開源框架TLog核心原理架構解析

鉑賽東發表於2021-03-29

前言

最近在做TLog 1.2.5版本的迭代,許多小夥伴之前也表示說很想參與開源專案的貢獻。為了讓專案更好更快速的迭代新特性以及本著發揚開源精神互相學習交流,很有幸招募到了很多小夥伴與我一起前行。

為了方便大家理解TLog專案的核心原理和架構,便有了此篇內容。此篇內容偏向TLog技術設計和核心原理,同時也涵蓋著做一個開源框架所需要考慮的問題和技術要點。

我一直相信,好的技術內容應提領關鍵點,引導大家該去如何讀懂原始碼。而不是全篇的貼程式碼。所以此篇也不是原始碼解析,而是提煉關鍵點,讓大家如何的更好去理解。

因為閱讀者在某些點上可能會有知識盲區,為了講了細緻,在某些點上我儘可能附加了延伸閱讀。知道相關知識點的同學,可以直接跳過。

還有,如果你是第一次閱讀到此篇內容,不知道TLog是什麼專案,則可以移步Gitee的託管倉庫以及專案主頁去檢視專案特性:

gitee託管倉庫:https://gitee.com/dromara/TLog

github託管倉庫: https://github.com/dromara/TLog

專案主頁: https://yomahub.com/tlog/

你也可以看之前釋出的一篇介紹TLog文章

https://mp.weixin.qq.com/s/-lalQBIUqxU2RW4RWHHvNw

模組

瞭解一款開源框架,首先從模組開始瞭解,TLog定位是一款輕量級日誌追蹤框架,它由10個模組組成

file

首先TLog既然是一款日誌框架,日誌增強就是它的核心,得適配主流的日誌框架(log4j / log4j2 /logback),這些最主要的邏輯和最核心的功能實現都在tlog-core模組中(以後可能還會單獨拆出3個日誌框架的單獨模組)。

其次,TLog能夠進行日誌追蹤,自然要適配微服務架構,支援RPC框架/協議(dubbo / dubbox / spring cloud feign / http)。由於每種RPC框架有自己的擴充套件點,自然不可能抽象寫出統一的處理邏輯。所以就有了以下模組:

tlog-dubbo為對接apache dubbo的適配模組

tlog-dubbox為對接早期的當當的dubbox開源版本,因為有的公司還在用

tlog-feign 為對接spring cloud feign的適配模組

tlog-webroot為對接最普通的http呼叫適配模組

考慮到用spring cloud的很多公司都會用spring全家桶的spring cloud gateway,所以就有了適配spring cloud gateway的適配模組tlog-gateway

在spring支援方面,tlog支援了傳統spring的xml配置結構,也支援了springboot的自動裝配。由於spring是springboot的子集,所以必定有2個模組,所以就有了tlog-alltlog-all-springboot-starter。之所以要加上all字樣,因為這2個包也是開發者引用的門面包,這2個提供單獨的依賴地址,會把所需要其他的tlog包一起依賴帶入。這樣就不用一個個去宣告依賴了。

TLog提供了基於javaagent的無依賴使用方式,所以就有了tlog-agent模組。在打包時,會單獨打成一個jar包。

其他tlog模組所公共使用的一些VO,列舉,util類則抽出來形成一個單獨的模組,所以就有了tlog-common

模組之間的依賴關係圖如下:

file

啟動裝載

TLog大約有80%的工作都是啟動時完成的,所以第一步就要弄清楚TLog隨著專案啟動時幹了些什麼。

由於springboot有自動裝配功能,所以只需要弄清楚tlog-all-springboot-starter自動裝配了什麼,就可以瞭解非springboot專案那些手動配置xml的意義了。

不清楚springboot自動裝配功能的同學,可以先去了解下這塊的知識,我覺得這篇文章講的比較透徹,可以延伸閱讀下:

https://zhuanlan.zhihu.com/p/95217578

TLog在springboot環境下所有自動裝配的配置類,都在spring.factories中體現:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.yomahub.tlog.springboot.TLogPropertyConfiguration,\
  com.yomahub.tlog.springboot.TLogWebAutoConfiguration,\
  com.yomahub.tlog.springboot.TLogFeignAutoConfiguration,\
  com.yomahub.tlog.springboot.TLogAspectAutoConfiguration,\
  com.yomahub.tlog.springboot.TLogCommonAutoConfiguration,\
  com.yomahub.tlog.springboot.TLogGatewayAutoConfiguration

TLogPropertyConfiguration主要用來自動裝配的是TLog配置初始化器,最終注入的是TLogPropertyInit,在傳統spring環境下,也只需要單獨配置TLogPropertyInit的xml就可以了,所以兩種spring環境形成最終的統一。

TLogWebAutoConfiguration主要用來自動裝配http協議的攔截器。

TLogFeignAutoConfiguration主要用來自動裝配spring cloud feign環境下的攔截過濾器。

TLogAspectAutoConfiguration主要用來自動裝配自定義標籤的切面,spring會自動為切中的類生成動態代理注入上下文。

TLogCommonAutoConfiguration主要用來自動裝配基於spring上下文的工具類。在很多不在spring容器管理中的bean想獲取spring上下文中的bean時,都會用到這個工具類。

TLogGatewayAutoConfiguration主要用來自動裝配spring cloud gateway環境下的攔截過濾器。

只要註冊了以上的自動裝配類,在springboot環境下,啟動時都會幫你自動裝配好。但是在傳統spring下,你還是得在xml中一個個的配置。所以開源專案支援springboot是很有必要的。

這些自動裝配的順序,也並不是按照配置的順序進行的,有先後依賴關係。具體可以仔細研究原始碼,原始碼註釋有寫。

如果有人不知道如何控制springboot自動裝配的順序的話 ,推薦看我之前寫的一篇文章,專門針對這個知識點進行了解讀

https://mp.weixin.qq.com/s/-7kTj7lWrlmHqjH6Yx2Nfw

那不知道會不會有人問,那dubbo/dubbox,三大日誌框架的增強就不需要註冊自動裝配器麼?

這裡一一解釋:

dubbo/dubbox,在設計時就有基於spi的實現,能夠自動識別出擴充套件的外掛,所以無需註冊任何bean到spring容器,所以不需要裝配。

log4j&logback,位元組碼模式的話,在springboot/spring啟動前就得載入了。下文會說到。所以不在springboot/spring啟動階段裝配。至於日誌適配模式,由於需要開發者提前替換好相關的encoder,所以日誌框架在載入日誌配置檔案時就會做這件事。所以也不需要自動裝配任何東西。

log4j2的設計完全採用外掛式,他自己能掃描並識別到相關擴充套件外掛,所以也不需要在springboot/spring裝配時幹任何事。

Log框架的支援解析

對於log框架的支援是TLog的重點,主要都在tlog-core這個模組中。TLog接入有三種方式,javaagent接入,位元組碼接入,適配模式接入。接入方式和對應的類,有下圖:

file

其實可以發現,javaagent本質上也是利用位元組碼的方式進行,區別是,javaagent的jar包外接,不用專案依賴。而位元組碼方式,需要依賴,並且要在啟動類裡面手動新增AspectLogEnhance.enhance()程式碼進行觸發。

還可以發現,javaagent模式和位元組碼模式目前是不支援非同步日誌的。只有適配模式才能支援。

可能會有人有疑問,上圖為什麼沒提到log4j2呢。

答:因為之前也說了,log4j2是外掛形式,從本質上來講。log4j2的生效方式只有一種,log4j2自動會去檢測外掛,嚴格的說,log4j2日誌增強的方式不屬於上面任何一種。也不需要任何裝配,任何觸發條件,只需要定義相關外掛就可以了。具體log4j2的外掛定義在tlog-core的如下包裡:

com.yomahub.tlog.core.enhance.log4j2

Log框架中的MDC

TLog對3大日誌框架的MDC也有支援,具體三個支援類在以下路徑

log4j: com.yomahub.tlog.core.enhance.log4j.AspectLog4jMDCPatternConverter
logback: com.yomahub.tlog.core.enhance.logback.AspectLogbackMDCConverter
log4j2: com.yomahub.tlog.core.enhance.log4j2.AspectLogLog4j2MDCConverter

要注意的是,這3個類,並不是直接對MDC作處理,這3個類的作用是:檢測log配置是否用了MDC

如果檢測到配置檔案有用mdc,則在TLog執行緒上線文中設定一個標記

TLogContext.setHasTLogMDC(true);

而真正對MDC進行處理的是這個類TLogRPCHandler,這個類是所有rpc呼叫的一個抽象層,裡面有以下程式碼進行了MDC的處理邏輯:

...
//如果有MDC,則往MDC中放入日誌標籤
if (TLogContext.hasTLogMDC()) {
   MDC.put(TLogConstants.MDC_KEY, tlogLabel);
}

如果這個標記為true,則用slf4j的MDC API進行設值

RPC支援

TLog對於RPC的支援,主要用到的是各個RPC框架自己的攔截器和過濾器來實現。

dubbo/dubbox

dubbo和dubbox是使用dubboFilter來實現,其原理2者一致。程式碼也都差不多。因為包路徑和個別類命名有區別,所以分成了2個模組,這裡放在一起講

其主要的處理類為TLogDubboFilterTLogDubboxFilter,之前有提到過,dubbo/dubbox有自己的SPI,能檢測出外掛。定義dubbo的外掛方式如下:

@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order = -10000)
public class TLogDubboFilter extends TLogRPCHandler implements Filter {
	...
}

dubbo/dubbox這裡分provider端和consumer端去處理,A->B,A就是consumer,B就是provider。2端的處理邏輯不一樣。

provider端:接受隱式傳參裡的引數-->處理引數-->放入tlog的執行緒上下文-->呼叫原有業務邏輯

consumer端:從tlog執行緒上下文中獲得引數-->處理引數-->呼叫遠端業務邏輯

feign/http

在spring cloud feign的場景,一般用feign作為consumer,普通的controller作為provider。所以這2個放到一起講。

feign主要的處理類為TLogFeignFilter,作為consumer端,大致做了如下事情:

從tlog執行緒上下文中獲得引數-->引數處理-->放入http header-->請求http

而Controller處理類主要為TLogWebInterceptor,作為provider端,大致做了如下事情:

從http header中接受到標籤引數-->處理引數-->放入tlog執行緒上下文-->呼叫原有業務邏輯

自定義標籤

自定義標籤是TLog中一個特色功能模組,能讓使用者自己定義標籤編入log日誌中。

其主要的處理類就一個aop,為AspectLogAop,位置在tlog-core中。

其主要思想就是去切@TLogAspect標籤,然後解析相關引數,最後把結果append到執行緒上下文的標籤值中。

這裡面涉及了標註的解析,點操作符的解析和值的獲取等操作。想弄明白,直接看AspectLogAop這個類就可以了。

其他功能

TLog還有其他輔助功能。

對mq中介軟體的支援:程式碼在tlog-corecom.yomahub.tlog.core.mq這個包中

自動列印引數和呼叫時間:在RPC的filter下面,會有XxxInvokeTimeFilter

非同步執行緒支援/執行緒池的支援:程式碼在tlog-corecom.yomahub.tlog.core.thread

自定義TraceId生成器:程式碼在tlog-commoncom.yomahub.tlog.id

以上所有功能的程式碼理解,結合著使用文件去閱讀理解,應該很容易弄懂,就不作解讀了

關於我

我是一個開源作者,也是一名內容創作者。「元人部落」是一個堅持做原創的技術科技分享號,會一直分享原創的技術文章,陪你一起成長。

wx

相關文章