log4jdbc-log4j2淺析(sqlfx客戶端採集日誌的來源)-java 輸出sql執行時間

前言

我們公司現在強制要求每個項目必須集成sqlfx客戶端,然後把項目輸出的jdbc日誌收集到sqlfx服務器端進行分析,根據配置將分析報告以郵件的形式發給相關人員。
但是大家有沒有思考過logback爲何可以把sql執行時間輸出到日誌文件中呢?或者有沒有遇到過明明把公司的logback.xml(logback-spring.xml)模板複製到項目中了,爲啥別的日誌都輸出好好的,偏偏就沒有輸出sql相關日誌呢?日誌文件也生成了,爲啥裏面沒內容呢?

主體

其實logback本身是沒有格式化sql輸出日誌功能的,我們項目能輸出sqlfx可以識別的jdbc日誌,完全是xxx-log4jdbc-log4j2的功勞。下面我們就基於目前的xxx-log4jdbc-log4j21.17.1-SNAPSHOT版本一起看一下他的真實面目吧(後續代碼均基於xxx-log4jdbc-log4j21.17.1-SNAPSHOT)。

1、組件集成

使用公司的logback模板我就不說了(springboot推薦使用logback-spring.xml,並且集成xxx-client-spring-boot-starter3.1.3版本)
同時還需要我們做兩件事兒:把連接池驅動改爲net.sf.log4jdbc.sql.jdbcapi.DriverSpy(必須),url改爲jdbc:log4jdbc:DatabaseTypeName://IP:PORT/DBName?Charset=utf8&currentSchema=SchemaName&AppName=AppName;引入log4jdbc.log4j2.properties配置(springboot項目可以在yml中配置,引入sqlfxClient-3.1.3版本即可),把實際驅動類配置一下。
做完上面這些事兒我們再去跑項目,你就會發現大功告成,sql信息被輸出了,那麼他咋實現的呢?

2、問題及答案探索

問題1:爲啥驅動類要改成net.sf.log4jdbc.sql.jdbcapi.DriverSpy



log4jdbc的驅動類DriverSpy和DatabaseTypeName的驅動類Driver均是集成java.sql.Driver,其實可以把前者理解爲統一的一個驅動代理,實際執行sql命令的還是各個數據庫的驅動,只不過由log4jdbc在上層代理了一下,這時候他就可以做一些小動作,其中拼接sql佔位及sql執行時間就是他做的小動作。

問題2:連接串要改成啥樣?


在原連接串的中間加上log4jdbc即可,jdbc:log4jdbc:實際驅動類,例如原串jdbc:DatabaseTypeName://IP:PORT...改成jdbc:**log4jdbc**:DatabaseTypeName://IP:PORT...即可。
DriverSpy類中有個log4jdbcUrlPrefix屬性,就是配置前綴的,後面他會截取咱們配置urljdbc:log4的後面部分,你會發現,咦,不就變成原始連接串了嗎?寫這個工具的人還真是聰明呀!

問題3:驅動類在什麼時候在哪兒加載的?


上圖可看到DriverSpy類裏面有一個靜態代碼塊,首次調用該類時就會觸發整個驅動初始化的邏輯

主要還是看這裏,我們在log4jdbc.log4j2.properties中配置的驅動會在這裏被讀取出來並加載,並且會先加載自己本身。

配置項爲log4jdbc.drivers,而且看到沒有?他支持用英文逗號分隔配置多個

配置文件中直接配置即可

有點兒注意事項

這裏針對mysql及oracle增加了特殊配置類


這幾個類都繼承自net.sf.log4jdbc.sql.rdbmsspecifics.RdbmsSpecifics,裏面只有一個主要的formatParameterObject,是用於拼接參數時格式化成對應數據庫腳本用的


爲啥咱們的sql日誌裏面帶了##^^##這個符號知道了不?奧祕就在這裏

問題4:sql執行時間是如何輸出的?

其實吧,雖然我不想這樣說,但實際上他的底層也是用方法執行結束時的System.currentTimeMillis()減去方法執行開始時的System.currentTimeMillis()來實現的,並且做了格式化,就是這麼簡單


看看這裏的說明,如果啓用了日誌的開關,則獲取連接時返回的是經過封裝的連接,若未開啓日誌開關,則返回真實的連接實例


看到沒?紅框裏面,就是那兩個代碼起到了輸出sql執行時間的關鍵作用!!!


上圖是他的實例化代碼


可以看到內部還是做了很多事兒的,並且也記錄下來了實際的db連接對象(跟數據庫連接池的理念一樣,都是緩存下來,以供實際使用的時候代理操作)


裏面方法也是挺全的,跟普通的Connection對象沒啥區別,只不過內部都是做了適配的


只要連接是經過代理的,那麼裏面所有的東西就都用代理了


跟ConnectionSpy基本一樣,只不過加了用於處理特殊參數的對象


也是做了一層封裝,畢竟實現了內一套接口,大家都一樣


重中之重就在這裏啦 看到紅框沒?他就是這樣幫我們計算腳本執行耗時的


通知logger對象,起牀尿尿啦


這裏是具體打印步驟,第一個紅框裏面就是咱們常說的“超過多少毫秒會自動升級爲error級別日誌”

結語

具體項目怎麼配置log4jdbc請參考我的另一篇文章 (內部資料,已隱藏。其實就是一個日誌客戶端組件,沒啥特殊的)
網上關於log4jdbc的一些資料
http://log4jdbc.brunorozendo.com/
https://zacard.net/2015/09/24/log4jdbc20150924/
http://blog.oneapm.com/apm-tech/178.html
https://blog.csdn.net/blueheart20/article/details/26471019

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章