上一篇文章中, 講了Java經常使用的日誌庫以及之間的關係,如今來講說咱們在項目中怎麼使用日誌庫。
apache
1. 老是使用Log Facade,而不是具體Log Implementationmaven
正如以前所說的,使用 Log Facade 能夠方便的切換具體的日誌實現。並且,若是依賴多個項目,使用了不一樣的Log Facade,還能夠方便的經過 Adapter 轉接到同一個實現上。若是依賴項目使用了多個不一樣的日誌實現,就麻煩的多了。函數
具體來講,如今推薦使用 Log4j-API 或者 SLF4j,不推薦繼續使用 JCL。url
2. 只添加一個 Log Implementation依賴spa
毫無疑問,項目中應該只使用一個具體的 Log Implementation,建議使用 Logback 或者Log4j2。若是有依賴的項目中,使用的 Log Facade不支持直接使用當前的 Log Implementation,就添加合適的橋接器依賴。具體的橋接關係能夠看上一篇文章的圖。debug
3. 具體的日誌實現依賴應該設置爲optional和使用runtime scope日誌
在項目中,Log Implementation的依賴強烈建議設置爲runtime scope,而且設置爲optional。例如項目中使用了 SLF4J 做爲 Log Facade,而後想使用 Log4j2 做爲 Implementation,那麼使用 maven 添加依賴的時候這樣設置:code
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> <optional>true</optional> </dependency>
設爲optional,依賴不會傳遞,這樣若是你是個lib項目,而後別的項目使用了你這個lib,不會被引入不想要的Log Implementation 依賴;orm
Scope設置爲runtime,是爲了防止開發人員在項目中直接使用Log Implementation中的類,而不適用Log Facade中的類。blog
4. 若是有必要, 排除依賴的第三方庫中的Log Impementation依賴
這是很常見的一個問題,第三方庫的開發者未必會把具體的日誌實現或者橋接器的依賴設置爲optional,而後你的項目繼承了這些依賴——具體的日誌實現未必是你想使用的,好比他依賴了Log4j,你想使用Logback,這時就很尷尬。另外,若是不一樣的第三方依賴使用了不一樣的橋接器和Log實現,也極容易造成環。
這種狀況下,推薦的處理方法,是使用exclude來排除全部的這些Log實現和橋接器的依賴,只保留第三方庫裏面對Log Facade的依賴。
好比阿里的JStorm就沒有很好的處理這個問題,依賴jstorm會引入對Logback和log4j-over-slf4j的依賴,若是你想在本身的項目中使用Log4j或其餘Log實現的話,就須要加上excludes:
<dependency> <groupId>com.alibaba.jstorm</groupId> <artifactId>jstorm-core</artifactId> <version>2.1.1</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> </exclusion> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> </exclusions> </dependency>
5. 避免爲不會輸出的log付出代價
Log庫均可以靈活的設置輸出界別,因此每一條程序中的log,都是有可能不會被輸出的。這時候要注意不要額外的付出代價。
先看兩個有問題的寫法:
logger.debug("start process request, url: " + url);
logger.debug("receive request: {}", toJson(request));
第一條是直接作了字符串拼接,因此即便日誌級別高於debug也會作一個字符串鏈接操做;第二條雖然用了SLF4J/Log4j2 中的懶求值方式來避免沒必要要的字符串拼接開銷,可是toJson()這個函數倒是都會被調用而且開銷更大。
推薦的寫法以下:
logger.debug("start process request, url:{}", url); // SLF4J/LOG4J2 logger.debug("receive request: {}", () -> toJson(request)); // LOG4J2 logger.debug(() -> "receive request: " + toJson(request)); // LOG4J2 if (logger.isDebugEnabled()) { // SLF4J/LOG4J2 logger.debug("receive request: " + toJson(request)); }
6. 日誌格式中最好不要使用行號,函數名等字段
緣由是,爲了獲取語句所在的函數名,或者行號,log庫的實現都是獲取當前的stacktrace,而後分析取出這些信息,而獲取stacktrace的代價是很昂貴的。若是有不少的日誌輸出,就會佔用大量的CPU。在沒有特殊須要的狀況下,建議不要在日誌中輸出這些這些字段。
最後, log中不要輸出稀奇古怪的字符!
部分開發人員爲了方便看到本身的log,會在log語句中加上醒目的前綴,好比:
logger.debug("========================start process request=============");
雖然對於本身來講是方便了,可是若是全部人都這樣來作的話,那log輸出就無法看了!正確的作法是使用grep 來看只本身關心的日誌。