在JAVA中記錄日志的十個小建議


JAVA日志管理既是一門科學,又是一門藝術。科學的部分是指了解寫日志的工具以及其API,而選擇日志的格式,消息的格式,日志記錄的內容,哪種消息對應於哪一種日志級別,則完全是基於經驗。從過去的實踐證明,JAVA的日志記錄會嚴重的影響性能。我也曾多次親眼見到在DEBUG模式下運行的在線股票交易程序,比在WARN或是其它更高層次模式下運行時延時要嚴重的多。延時和速度是任何電子交易平台或是股票交易平台的一個重大關注點,所以我們必須了解並掌握JAVA日志及其最佳實踐。這不僅僅只是為了用在金融或是投資銀行領域,它適用於所有既追求速度又需要日志功能的應用。

為何需要日志

這是一個很基本的爭議,人們會爭辯說,我們可以使用System.out.println()來打印消息,為何還需要日志呢?每個人剛開始接觸JAVA時,都使用System.out.println()在控制台打印消息。但是它的功能遠遠沒有日志記錄API如log4j或是java.util.logging強大。如果你正在寫一個java服務器應用,那么你只有通過日志文件才能知道你的服務器在做什么。如果你沒有記錄任何日志,那么沒有人知道你的服務器在干啥。而如果你的服務器作為一個中間件連接到應用中時,比如從股票交易系統或是電子交易系統獲得輸入流,將其轉換並標准化后發送到輸出流,這時日志就更為重要。沒有日志你根本不知道究竟哪里出了問題。因此,日志在JAVA中是必不可少的。

JAVA中有哪些不同的日志級別

使用過JAVA日志的童鞋一定知道這些基礎的日志級別比如DEBUG, INFO, WARN和ERROR

DEBUG是最低的限制級別。這個級別只能用於開發和測試環境中,不可以用於生產環境。

INFO略高於DEBUG的限制級別,我們應該用這個級別記錄一些信息型消息比如服務器啟動成功,輸入的數據,輸出的數據等等。

WARN的限制級別高於INFO,它用來記錄警告信息比如客戶端和服務器之間的連接中斷,數據庫連接丟失,Socket達到上限。這些信息是最為重要的,因為你可以在這些信息出現時發出警告,從而讓運維團隊管理應用程序的運行,並及時處理這些報錯。

ERRORWARN的限制級別還高,用於記錄ERRORException。你可以在該日志級別上設置警報裝置,並且提醒運維團隊對之做出處理。ERROR非常重要,你必須將其記錄下來。

FATAL是指可能導致程序終止的非常嚴重的時間。在這種事件之后你的應用很可能會崩潰。

OFF具有最高的級別,旨在關閉JAVA中的日志功能。

這些日志級別是根據slf4j整理的,和java.util.loggingAPI中定義的級別不太一樣。java.util.logging還提供了其它的基於問題嚴重性進行划分的日志級別如SEVERE, FINER, FINEST, FATAL 等。

使用log4j還是java.util.logging

 

我會推薦使用log4j,你可能會對此持有異議。我也同意java.util.logging的功能很強大,但是我發現log4j更易於使用。你已經了解了log4j的各個日志級別,這里每個級別都非常恰當的描述了其功能。log4j還提供了額外的靈活性,你無需重新啟動應用來改變日志的級別。當然,你也可以在java.util.logging中通過JMX實現這個功能。

log4j還允許我們在配置文件log4j.xml中設置每個類的日志級別。你既可以使用XML文件也可以使用properties文件進行配置。而且log4j是線程安全的。它被設計用於高並發的系統中。在另一方面,我發現java.util.logging中的FormatterAppender功能非常棒。

為何在JAVA中使用日志會影響性能

通常來說,記錄日志越頻繁,所需的IO操作就越多,從而影響了應用的性能。因此為每一個消息選擇一個合適的日志級別是非常重要的。既然我們不能不使用JAVA日志,那么我們只能控制日志的級別以及在那個級別上記錄的日志內容。所以,一定要在isDebugEnabled()代碼塊中記錄DEBUG消息,如下所示:

if(logger.isDebugEnabled()){ logger.debug("java logging level is DEBUG Enabled") }

在生產環境中一定要使用WARN或是更高級別的日志記錄等級,一定不要使用DEBUG。它很可能成為性能下降的罪魁禍首。

JAVA日志的10個小建議

1.將DEBUG日志訪日isDebugEnabled代碼塊

它能顯著的減少因為字符串拼接而帶來的性能的影響。

2.謹慎的消息的等級

當你在編寫服務器端應用時,這一點顯得格外的重要,因為它是你觀察服務器運行情況的唯一途徑。如果你記錄了太多的日志,則會影響服務器的性能,但是如果你不記錄重要的信息如輸入數據和輸出數據,那么就很難識別究竟發生了什么問題。

3.使用slf4j或是java.util.loggin

我推薦slf4j因為它的靈活性非常高。它允許在不重啟應用的前提下更改日志級別。你可以通過log4j的看門狗來不停的尋找目錄中的log4j.xml配置文件,並且在找到后重置日志配置。

4.log4j可以為不同的類配置不同的日志級別

你可以將一些類設置為INFO級別,再將另一些類設置為WARN級別或是ERROR級別。

5.日志的格式化

不要忘了記錄線程的名稱和完整的JAVA類名,因為如果有多個線程同時在執行這段代碼,你可能根本找不出事件序列。在我看來,這一條建議最為重要

6.從日志中生成報告

在記錄日志時要保證一致性和信息性,從而可以分析日志。

7.使用前綴來說明哪一部分代碼在打印日志

前綴是指如客戶端,數據庫或是Session等等。之后你可以使用grep或是find來找到和這些關鍵字相關的日志。我在進行了這種實踐后發現它非常有助於debug或是調查事件,尤其是當日志文件很龐大的時候。你可以將所有數據庫級別的日志加上前綴DB_LOG,再將所有SESSION級別的日志加上前綴SESSION_LOG

8.如果某個日志沒有分配等級,則將其繼承最近級別的等級

這也是為什么我們總是將日志等級分配到根日志上log4j.rootLogger=DEBUG.

9.沒有日志和過度日志都是不好的

原因前面已經說明

10.自檢日志並調整日志

最好用英文記錄日志,而且要有良好的可讀性,從而在查閱時能夠快速理解日志。

11.使用標准化格式而不要自行拼接

logger.debug("No of Orders " + noOfOrder + " for client: " + client);//不好 logger.debug("No of Orders {} for client: {}", noOfOrder, client);

補充:記錄哪些信息以及各個信息對應什么級別的日志

1.不要記錄敏感信息

不要記錄敏感信息如密碼,身份證號,信用卡號或賬戶號。

2.盡量記錄決策性信息

比如,一個JAVA應用需要從偏好文件或是環境中加載配置,如果沒有找到就使用默認的配置。如果你在使用默認配置,那么你應當記錄如下信息:

logger.info("Not able to load personal settings, default Setting selected for user : {}", user);

這個日志丟失了一個關鍵性信息,為什么無法加載到個人配置?因此如果出現異常的話,還應當記錄異常。當然,這條日志也提供了有用的信息,比如究竟是哪個用戶遇到了這個問題。

3.一致性

一致性在日志和編碼中都很重要。無論你采用哪種格式,你都應當堅持一致性。你應當花些時間仔細考慮日志的格式,從而用它來捕獲有用的信息。

4.記錄一切出現問題時輔助debug的信息

舉個例子,我們經常在應用中將String轉化為Date,如果String的格式不正確的話,我們通常會拋出ParseException。但是我經常看到有的代碼里捕獲了這個異常之后,將Date賦值為null並打印如下日志:

logger.info("failed to convert String to date")

看到這行日志的時候,你根本不知道那個date傳入了不合法的值。它也沒有打印出不合法的String的內容究竟是什么。你需要這些信息來解決這個問題。一個更好的日志信息如下:

logger.info("invalid startDate: {}", startDate);

5.異常信息應該包括兩類信息:案發現場信息和異常堆棧信息。如果不處理,那么通過 關鍵字 throws 往上拋出。

logger.error(各類參數或者對象 toString + "_" + e.getMessage(), e); 

6.謹慎地記錄日志。

生產環境禁止輸出 debug 日志;有選擇地輸出 info 日志;如果使 用 warn 來記錄剛上線時的業務行為信息,一定要注意日志輸出量的問題,避免把服務器磁盤 撐爆,並記得及時刪除這些觀察日志。

轉自 https://segmentfault.com/a/1190000013366405


免責聲明!

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



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