今天我來分享一個關於日誌的問題和解法。 問題 沒有界面的後端程式在實際運行中發生了什麼事,通常是通過日誌來探查。所以日誌非常重要。資料庫記錄了程式運行的結果,日誌記錄了程式運行的過程。但是日誌經常出現一個問題,日誌量太多,以至於把重要的日誌淹沒在裡面。未能及時地發現問題,或者當有問題出現的時候,在日 ...
今天我來分享一個關於日誌的問題和解法。
問題
沒有界面的後端程式在實際運行中發生了什麼事,通常是通過日誌來探查。所以日誌非常重要。資料庫記錄了程式運行的結果,日誌記錄了程式運行的過程。但是日誌經常出現一個問題,日誌量太多,以至於把重要的日誌淹沒在裡面。未能及時地發現問題,或者當有問題出現的時候,在日誌中找原因真的是很痛苦。
對於這個問題,第1招就是把日誌進行分級,差不多是每一種日誌工具都提供了這個功能。常見的有info、warn、error這些級別。當使用級別進行過濾之後,往往發現日誌還是太多。就需要進一步分析原因了。
在實際項目中發現有這麼幾種情況:
1. 有大量的日誌,內容基本相同,只是有一兩個值不同。如“發現無法轉成long類型的字元串:xxx”
2. 還有一類日誌是內容完全相同,如“意外發現xxx屬性的值是null”
至於為什麼會有大量的這種日誌,大概率是它在迴圈內部,甚至是多重迴圈的內部。
解法
解法一:少寫日誌
怕日誌多而在寫日誌代碼時猶豫,甚至就不寫了。當出問題後找不到日誌,無法為定位問題提供幫助。此法不可取。
解法二:硬編碼控制日誌數量
設置一些標誌或計數器來使迴圈內的同一類日誌只列印一條或少數幾條,那麼日誌的邏輯跟業務的邏輯會混在一起,程式的整體邏輯變得複雜。此法是下策。
如何讓程式員大膽寫日誌,而又不會出現日誌太多,同時日誌的邏輯也很少摻雜到業務邏輯中呢?
解法三:日誌工具類
我寫了一個日誌的實用類來解決這個問題。
1. 拼接
它是將多條日誌拼接為一條來輸出。採用“首碼+主體+尾碼”的形式,在初始化時設置好首碼和尾碼,在接收日誌條目時拼接條目,最後的輸出形式是“首碼+條目1, 條目2, …+尾碼”。如果條目數為0,則前尾碼都不會輸出。所以,“發現無法轉成long類型的字元串:aaa”,“發現無法轉成long類型的字元串:bbb”“發現無法轉成long類型的字元串:ccc”,會拼接這樣一條:“發現無法轉成long類型的字元串:aaa,bbb,ccc”。合成後的內容長度就大大減少。
2. 條目數限制
假如類似的情況發生1000次,拼接後的日誌還是很長。作為人來講,只需要看到前面的若幹條目,就瞭解了這個問題,通常是沒必要看到全部的值。所以這個日誌工具提供了條目數的限制,對於超過限制的條目,則不會輸出。比如條目數的限制是2,那輸出的結果就是“發現無法轉成long類型的字元串:aaa,bbb”
3. 同值合併
對於內容完全相同的日誌,就會直接進行合併,並記錄一個次數,不相鄰的除外。原本是好幾屏幕的“意外發現xxx的值是null”。合併成一條:“[1000*]意外發現xxx的值是null”。(此法是向瀏覽器的控制台學習)
4. 長度限制
除此之外,還提供了總長度的限制,即是對“首碼+條目1, 條目2, …+尾碼”的總長度的限制。如果某個條目加進去之後整體長度超過這個限制了,那麼這個條目就會被丟棄。首碼尾碼是不會被丟棄的,但如果“首碼+尾碼”已經超出限制了,根據“如果條目數為0,則前尾碼都不會輸出”最終沒有輸出。
5. 異常
此日誌類實現特定的介面(Closable),做到了即使在業務代碼發生異常的情況下,也不會漏了輸出優化後日誌。用法:
try (LogUtil log = LogUtil.builder().logger(LOGGER).build()) {
// ...A
log.write(“any message”);
// ...B
}
如果A處發生異常,自然沒有任何輸出。如果B處發生異常,則不影響前面的“any message”的輸出。
以上的條目數限制、同值合併、總長度限制等功能可單獨使用,也可組合使用。所以可能會看到這樣的結果:
“發現無法轉成long類型的字元串:aaa,bbb,[99*]aaa,[56*]ccc”
這個日誌實用工具是對現有日誌組件的封裝,而現有的日誌組件是log4j。不管使用哪個日誌組件,都可以加上這種封裝。我並沒有修改日誌組件,只是給他套了一層“殼”。
實際投入使用後,在我們的項目中發現,有一種相同的日誌產生了947條,在過去是刷了好多屏,而且還不知道他多少條,現在合成之後就是一條,並且打上了“[947*]”,不僅沒有刷屏,還很清晰的看到了條數。
乾凈,舒服。
博主簡介:佘煥敏(shé),洋名 Billy Sir。
關註編程基礎技術,並致力於研究軟體的自動化生成。 對編程規範化、面向對象的極致使用也有著濃厚的興趣。 同時非常希望能夠寫程式到65歲。
只有工匠精神,才能把常人覺得單調乏味的代碼,當作作品雕刻成藝術品。