在我工做過的公司裏,有一家公司的代碼裏所有都是日誌,而另一家則是一行日誌記錄都沒有。css
可是在線上環境中,日誌記錄是很是重要的,它能幫咱們快速定位問題所在。整理以後,我發現下面幾點關於日誌的建議是很是有效的。html
用過 類 Unix 系統的人都知道,Unix 系統的提示哲學是沒提示就是最好的提示。若是一個命令執行成功了,那麼系統是不會提示的,只有當執行出錯的時候纔會報錯。反觀咱們的代碼,通常狀況下咱們的代碼99%都是正常的執行路徑,不會出現邏輯異常或代碼異常,只有1%的時候纔會出現異常。在這種狀況下,咱們固然是選擇在那1%的地方進行日誌輸出了。因此寫日誌咱們應該達成一個共識,那就是:只在邏輯異常或代碼異常的地方加上日誌提示。java
在咱們討論「沒有提示就是最好的提示」時,咱們只是站在程序猿的角度來思考如何寫提示,可是有時候閱讀日誌的人多是nginx
對於不一樣的」誰」,你將要寫下的log信息的內容,上下文,類別和level會大不一樣。開發者瞭解程序內部,因此給他的log信息能夠比給終端用戶的複雜得多。因此爲了兼顧其餘人對於程序的理解,有時候須要在一些重要的業務邏輯裏增長一些與邏輯異常或代碼異常無關的一些代碼,如:在P2P項目中,當用戶完成充值的時候,你須要打印出用戶充值成功的信息。數據庫
簡單地說:咱們不只僅要在邏輯異常或代碼異常的地方加上日誌提示,並且也須要在每一個環節完成的時候輸出日誌提示,這樣會便於咱們進行線上問題的定位。安全
若是你使用了開源日誌框架,那麼你要對你程序中每個log語句使用不一樣的log級別。其中最困難的一個任務是找出這個log應該是什麼級別。在 SLF4J 中經常使用的級別有這麼幾個,他們的日誌級別從高到低是:ERROR > WARN > INFO > DEBUG。當代碼中的級別大於設置文件中設置的級別時,對應的日誌就會輸出。markdown
如下是個人一些建議:多線程
log 輸出模式能夠幫助咱們在日誌中增長一些清晰的上下文信息,不過對添加的信息仍是要多加當心。好比說,若是你是每小時輸出一個文件,這樣你的日誌文件名中已經包含了部分日期時間信息,所以就不必在日誌中再包含這些信息。另外在多線程環境下也不要在本身在日誌中包含線程名稱, 由於這個也能夠在模式中配置。框架
根據個人經驗, 一個理想的日誌模式將包含下列信息:運維
根據實際狀況,你還能夠添加下面一些信息:
但要記得,不要用反射去本身獲取文件名、類名等信息再去做爲日誌信息輸出,這樣會極大下降日誌效率。若是須要,你完成能夠在 SLF4J 的配置文件中進行配置。
若是你的程序被大多數人使用,而你又沒有足夠的資源作國際化,英語會成爲你的不二之選。
沒有什麼比這樣的log信息更糟的了
Transaction failed
或者
User operation succeeds
又或是API異常時:
java.lang.IndexOutOfBoundsException
沒有相應的上下文,這些信息不過是噪音,它們不會對調試過程當中有意義的數值或是空間起做用(add value and consume space)。帶上上下文的信息要有價值得多,例如:
Transaction 234632 failed: cc number checksum incorrect
或是:
User 54543 successfully registered e-mail<a href="mailto:user@domain.com">user@domain.com</a>
又或是:
IndexOutOfBoundsException: index 12 is greater than collection size 10
在上面這一例子中的異常,若是你想把它傳播開, 確保在處理的時候帶上與當前level相應的上下文,讓調試更簡單,以下一個 Java 的例子:
public void storeUserRank(int userId,int rank,String game) {
try {
...deal database ...
} catch (DatabaseException de) {
throw new RankingException("Can't store ranking for user "+userId+" in game "+ game + " because " + de.getMessage() );
}
}
使用佔位符更有利於代碼的閱讀,而且能夠提升性能。所以你應該寫這樣的日誌記錄:
logger.info("User {} login.", userId);
而不是這樣的:
logger.info("User " + userId + " login.");
在下面的日誌記錄中,若是 user 爲空,那麼將會拋出異常,那麼就會直接致使程序中斷。
logger.info("User {} login fail.", user.getUserInfo);
所以在日誌記錄中,要避免日誌中發生異常而致使正常的業務邏輯受到影響,這是絕對不容許出現的。
紙上得來終覺淺,說了這麼多,但仍是要實踐時不斷去應用,去提取適合本身的日誌規則,這樣才能寫出好的代碼。
出處:http://www.cnblogs.com/chanshuyi/p/how_to_write_log_in_code.html