大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

用Java日志來寫詩


工欲善其事,必先利其器

很多程序員可能都忘了記錄應用程序的行為是一件多么重要的事,當遇到多線程環境下高壓力導致的并發bug時,你就能體會到記錄log的重要性。

有的人很高興的就在代碼里加上了這么句:

log.info("Happy and carefree logging");

 

他可能都沒有意識到應用程序的日志在維護,調優和故障識別中的重要性。

我認為slf4j是非常好的日志API,主要是因為它支持一個很棒的模式注入的方式:

log.debug("Found {} records matching filter: '{}'", records, filter);

 

log4j的話你只能這樣:

log.debug("Found " + records + " recordsmatching filter: '" + filter + "'");

 

這樣寫不僅更啰嗦和可讀性差,而且字符串拼接影響效率(當這個級別并不需要輸出的時候)。

slf4j引入了{}注入特性,并且由于避免了每次都進行字符串拼接,toString方法不會被調用,也不再需要加上isDebugEnabled了。

slf4j是外觀模式的一種應用,它只是一個門面。具體實現的話我推薦logback框架,之前已經做過一次廣告了,而不是已經很完備的log4j。它有許多很有意思的特性,和log4j不同的是,它還在積極的開發完善中。

還有一個要推薦的工具是perf4j

Perf4J is to System.currentTimeMillis() as log4j is to System.out.println()

就好比log4jSystem.out.println的一種更好的替換方式一樣,perf4j更像是System.currentTimeMillis()的替代。

我已經在一個項目中引入了perf4j,并在高負載的情況下觀察它的表現。管理員和企業用戶都被這個小工具提供的漂亮的圖表驚呆了。

我們可以隨時查看性能問題。perf4j應該專門開一篇文章來講,現在的話可以先看下它的開發者指南。

還有一個Ceki Gülcülog4j,slf4jlogback工程的創建者)提供了一個簡單的方法供我們移除對commons-logging的依賴。

不要忘了日志級別

每次你要加一行日志的時候,你都會想,這里該用哪種日志級別?大概有90%的程序員都不太注意這個問題,都是用一個級別來記錄日志,通常不是INFO就是DEBUG。為什么?

日志框架和System.out相比有兩大優勢:分類和級別。兩者可以讓你可以選擇性的過濾日志,永久的或者只是在排查錯誤的時候。

1.ERROR 發生了嚴重的錯誤,必須馬上處理。這種級別的錯誤是任何系統都無法容忍的。比如:空指針異常,數據庫不可用,關鍵路徑的用例無法繼續執行。

2.RN 還會繼續執行后面的流程,但應該引起重視。其實在這里我希望有兩種級別:一個是存在解決方案的明顯的問題(比如,當前數據不可用,使用緩存數據),另一個是潛在的問題和建議(比如程序運行在開發模式下或者管理控制臺的密碼不夠安全)。應用程序可以容忍這些信息,不過它們應該被檢查及修整。

3.BUG 開發人員關注的事。后面我會講到什么樣的東西應該記錄到這個級別。

4.ACE 更為詳盡的信息,只是開發階段使用。在產品上線之后的一小段時間內你可能還需要關注下這些信息,不過這些日志記錄只是臨時性的,應該關掉。DEBUGTRACE的區別很難區分,不過如果你加了一行日志,在開發測試完后又刪了它的話,這條日志就應該是TRACE級別的。

上面的列表只是一個建議,你可以根據自己的規則來記錄日志,但應該要有一定的規則。我個人的經驗是:在代碼層面不要進行日志過濾,而是用正確的日志級別能夠快速的過濾出想要的信息,這樣能節省你很多時間。

最后要說的就是這個臭名昭著的is*Enabled的條件語句了。有的人喜歡把每次日志前加上這個:

if(log.isDebugEnabled())
    log.debug("Place for your commercial");

 

個人認為,應該避免在代碼里加入這個亂哄哄的東西。性能看起來沒有什么提升(尤其是用了slf4j之后),更像是過早的優化。還有,沒發現這么做有點多余么?很少有時候是明確需要這種顯式的判斷語句的,除非我們證明構造日志消息本身開銷太大。不然的話,該怎么記就怎么記,讓日志框架去操心這個吧。

你清楚你在記錄什么嗎?

每次你寫下一行日志,花點時間看看你到底在日志文件里打印了些什么。讀一遍你的日志,找出異常的地方。首先,至少要避免空指針異常:

log.debug("Processing request with id: {}", request.getId());

 

你確認過request不是null了嗎?

記錄集合也是一個大坑。如果你用Hibernate從數據庫里獲取領域對象的集合的時候,不小心寫成了這樣:

log.debug("Returning users: {}", users);

 

slf4j只會在這條語句確實會打印的時候調用toString方法,當然這個很酷。不過如果內存溢出了,N+1選擇問題,線程餓死,延遲初始化異常,日志存儲空間用完了這些都有可能發生。

更好的方式是只記錄對象的ID(或者只記錄集合的大小)。不過收集ID需要對每個對象調用getId方法,這個在Java里可真不是件簡單的事。Groovy有個很棒的展開操作符(users*.id,Java里我們可以用Commons Beanutils庫來模擬下:

log.debug("Returning user ids: {}", collect(users, "id"));

 

collect方法大概是這么實現的:

public static Collection collect(Collection collection, String propertyName) {
    return CollectionUtils.collect(collection, new BeanToPropertyValueTransformer(propertyName));
}

 

最后要說的是,toString方法可能沒有正確的實現或者使用。

首先,為了記錄日志,為每個類創建一個toString的做法比比皆是,建議用 ToStringBuilder來生成(不過不是它的反射實現的那個版本)。

第二,注意數組和非典型的集合。數組和一些另類的集合的toString實現可能沒有挨個調用每個元素的toString方法。可以使用JDK提供的Arrays#deepToString方法。經常檢查一下你自己打印的日志,看有沒有格式異常的一些信息。

更多Java培訓Java視頻Java教程盡在動力節點Java培訓,關注動力節點官方微信,獲得一手Java全新知識

 

上一篇:Java 線程池框架核心代碼分析
下一篇:再駁Java將死的謠言

開班信息

主站蜘蛛池模板: 国产免费一级精品视频 | 亚洲综合日韩精品欧美综合区 | 亚洲精品一线观看 | 国产3344永久在线观看视频 | 手机福利在线观看 | 免费一级特黄视频 | 亚洲专区欧美 | 亚洲九月天 | 亚洲精品一区二区卡 | 欧美乱大交xxxxxx喷潮免费 | 日本中文一区 | 一级无毛| 久久99国产精品成人 | 黑人超长巨大xxxxxxx视频 | 97在线视频免费观看费观看 | 亚洲精品www久久久久久久软件 | 国产成人精品一区二区三在线观看 | 亚洲中字在线 | 久久精品国产久精国产果冻传媒 | 欧美曰韩免费视频一区 | 日韩女人做爰大片 | 国产精品9999久久久久 | 91在线 | 欧美| 久在草影院 | 天天玩夜夜操 | 国产欧美国产精品第一区 | 996re免费热在线视频手机 | 精品一精品国产一级毛片 | 人人做天天爱夜夜爽中字 | 在线免费福利 | 国产一区二区精品久久岳 | 爱搞逼综合网 | 亚洲国产精品久久久天堂 | 成年女人色毛片免费看 | 九九精品激情在线视频 | 国产成人免费片在线观看 | 日韩精品中文字幕一区二区三区 | 国产精品久久久久久一级毛片 | 免费亚洲一区 | 大尺度福利视频在线观看网址 | 91精品91久久久 |