我們拋開業務邏輯,僅僅從日誌的角度來考慮日誌問題。集合最近對項目的日誌優化,總結以下幾點最佳實踐。
Slf4j + logback 打印日誌的最佳實踐
1,日誌級別使用不當
2,謹慎使用e.printStackTrace()
3,使用佔位符,而不是字符串拼接
4,儘量打印更少的日誌
5,儘量不要在for循環中log日誌
下面結合代碼,來具體講解。
1,日誌級別使用不當
Slf4j有四個級別的log level可供選擇,級別從上到下由低到高,優先級高的將被打印出來。
Debug:簡單來說,對程序調試有利的信息都可以debug輸出。
info:對用戶有用的信息,比如最常見的打印接口入參和返參。
warn:可能會導致錯誤的信息,比如某個對象可能爲null的場景判斷。
error:顧名思義,發生錯誤的地方,最常見的catch代碼塊中的日誌。
這裏以error日誌爲例,舉一個例子,在合適的場合打印合適的日誌,是我們日誌界的規範。
// ---------------- 1,日誌級別使用不當 ----------------
try{
String str = null;
str.length();
} catch(Exception e) {
// 這裏不推薦打印info日誌
logger.info("注意,這裏不要打印info日誌,", e);
// 正確的做法
logger.error("注意,這裏不要打印error日誌,", e);
}
2,謹慎使用e.printStackTrace()
e.printStackTrace()打印的是異常堆棧信息,會佔用內存空間。正確的姿勢是把日誌打印到文件中。
// ---------------- 2,謹慎使用e.printStackTrace() ----------------
try{
String str = null;
str.length();
} catch(Exception e) {
// 謹慎使用e.printStackTrace()
e.printStackTrace();
}
3,使用佔位符,而不是字符串拼接
Slf4j打印日誌使用了佔位符,避免了字符串拼接操作。字符串拼接最大的弊端,就是需要new新的字符串對象,增加了內存的開銷。
// ---------------- 3,使用佔位符,而不是字符串拼接 ----------------
String str = null;
String str2 = "五千年文明史";
try{
str.length();
} catch(Exception e) {
// 不推薦的做法,尤其是拼接的 字符串較多時,對性能有影響
logger.error("str:" + str + ", str2:" + str2, e);
// 正確的做法
logger.error("str:{}, str2:{}", str, str2, e);
}
4,儘量打印更少的日誌
日誌打印,要堅持一個原則:儘量打印更少的日誌。
因爲磁盤空間也是有限的,如果磁盤空間不足,會直接導致應用程序的崩潰。
好的做法是:不要打印無用的日誌,不要重複打印日誌,儘量不要在for循環中打印日誌。
// ---------------- 4,儘量打印更少的日誌 ----------------
String str1 = null;
String str2 = null;
String str3 = null;
try{
// 錯誤的做法
logger.info("str1:{}", str1);
logger.info("str1:{}", str1);
logger.info("str1:{}", str1);
// 正確的做法
logger.info("str1:{}, str2:{}, str3:{}", str1, str2, str3);
str.length();
} catch(Exception e) {
logger.error("str:{}", str, e);
}
5,儘量不要在for循環中log日誌
一般來說,for循環中的log日誌,都可以提到for循環外面來打印。因爲for循環的對象
是集合,而集合都可以轉化成對應的json字符串。
特殊情況,必須要在for循環中打印的,需要評估是否有必要,已經這個日誌的量級,看
是否太耗內存。
// ---------------- 5,儘量不要在for循環中log日誌 ----------------
try{
List<String> list = new ArrayList<>();
list.add("唐朝");
list.add("宋朝");
list.add("董仲舒");
// 不推薦的做法
for (String str : list) {
logger.info("str:{}", str);
// 業務邏輯代碼
}
// 推薦的做法
logger.info("list to json:{}", JSON.toJSON(list).toString());
for (String str : list) {
// 業務邏輯代碼
}
} catch(Exception e) {
logger.error("{} error", this.getClass().getSimpleName(), e);
}
如果是其他集合,同理,也可以轉化成json字符串,這裏不再贅述。