專案維護總結——日誌列印
日誌列印在開發中一般都是有2個極端,首先是什麼都不列印,出了問題之後一看後臺啥也沒有,然後修改;修改的結果就是什麼地方都列印,一出錯誤,找日誌找半天,定位一個問題要1,2個小時,甚至是更多的,之前遇到過一個開發團隊,定位解決一個問題用了三天(並不是什麼特別特殊的業務)。之前也出現過幾次前臺出錯沒有日誌,測試環境無法重現,把日誌加上走個變更再操作再看日誌定位的事情。
開發久了,總會遇到“這個問題生產環境上能重現,但是沒有日誌,業務很複雜,不知道哪一步出錯了?”,又或者“這幾行程式碼的異常被捕獲了,但是異常一直沒有打印出來” 這個時候,怎麼辦? 還能怎麼辦,發個版本,就是把所有地方加上日誌,沒有任何新功能,然後在讓使用者重現一遍,拿下日誌來看,呵呵,,原來是這個問題!。
還有另外一種場景:現在很多系統都是分散式的,一個系統有好多節點,出了問題找日誌真是痛苦,一個一個機器翻,N分鐘後終於找到了,找到了後發現好多相似日誌,一個一個排查;日誌有了,發現邏輯很複雜,不知道走到那個分支,只能根據邏輯分析,不停的翻看程式碼,半天過去了,終於找到了原因。。。一個問題定位就過去了2個小時,變更時間過去了一半。。。
—日誌要求基本—
1、能找到那個機器
2、 能找到使用者做了什麼
—開發日誌要求—
1、分支語句的變數需要列印變數
// optype決定程式碼走向,需要列印日誌 logger.info("edit user, opType:" + opType); if (opType == CREATE) { // 新增操作 } else if (opType == UPDATE) { // 修改操作 } else { // 錯誤的型別,丟擲異常 throw new IllegalArgumentException("unknown optype:" + opType); }
重要建議:養成把不合法引數丟擲異常的好習慣,拋異常的時候把對應的非法值丟擲來。
2、修改操作需要列印操作的物件
大部分問題都是修改導致的。資料修改必須有據可查。3、大量資料操作的時候需要列印資料長度
建議前後列印日誌,而且要打印出資料長度,目的是為了知道處理了多少資料用了多少時間
。如一個操作用了3秒鐘,效能是好還是壞?
如果處理了1條資料,那麼可能就是效能差,如果處理了10000條資料,那麼可能就是效能好。logger.info("query docment start ..."); List<Document> docList = query(params); logger.info("query docment done, size:" + docList.size())
4、使用log4j的MDC列印使用者名稱等額外資訊
有時候,業務量大的系統要找到某一個使用者的操作日誌定位問題非常痛苦,每一個日誌上加使用者名稱又低效也容易漏掉,所以我們要在更高層級上解決這些共性問題。
我們使用log4j的MDC功能達成這個目的。
在單點登入後,設定使用者資訊的時候,把使用者標誌放到MDC中。
private final static ThreadLocal<String> tlUser = new ThreadLocal<>();
public static final String KEY_USER = "user";
public static void setUser(String userid) {
tlUser.set(userid);
// 把使用者資訊放到log4j
MDC.put(KEY_USER, userid);
}
然後修改log4j配置,pattern上增加 %X{user}
,位置隨意。
增加執行緒相關配置 [%t]
,完整引數詳見log4j變數
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%t]%-d{MM-dd HH:mm:ss,SSS} %-5p: %X{user} - %c - %m%n" />/>
</layout>
參考文章:
https://zhuanlan.zhihu.com/p/28629319