看到這種代碼,我直接氣到想打人
1. 背景
上周五11點,上游業務急匆匆的拉我入群,說有一個大客戶反饋,他們賬戶無緣無故不能下單了。
多大的客戶呢?真的非常大,看了下他的賬戶授信額度上千萬的級別,這個客戶大家絕對都聽說過(做物流的一哥)。
嚇得我開會的心情的都沒了,直接去日志平臺排查問題。不看不知道,一看我的血壓直接飆升,心里開始罵人了。
這個系統是離職的同學暫時交給我的,現在處于只維護,不新增需求的狀態。
2. 代碼
簡化代碼如下:
@RequestMapping("/pay")
public void pay(PayReq req) {
// switch 讀取阿波羅配置
if (switch) {
aPay(req);
} else {
bPay(req);
}
}
public void aPay(PayReq req) {
// 里面去查了3-4張數據表,涉及5-6個阿波羅字段,才確定是哪個實現類
// payService 下面有5個繼承 serviceA, serviceB, serviceC, serviceD, serviceE...
payServiceA = xxxSelect.getPayService(req);
payServiceA.pay(req); // 里面至少5-6個rpc調用
}
看代碼,我頭都懵了,這下單的邏輯這么復雜,涉及到5-6個系統,10幾個數據庫表,好幾個不同的實現類,幾十個阿波羅的配置,分支繞來繞去。
但是日志平臺的\(\color{red}{日志只有3行!!!}\) 沒錯,只有3行,我當時都懵了,這shabi寫代碼的人,怎么一行日志都不打印,這特么怎么看。
我甚至都不知道你走了aPay,還是bPay。你走的哪個payService我都不知道,報錯是哪一行我都看不出來。當時真的無從下手。
不過最后客戶賬號又好了,也不知道原因。當然這不是今天的主題,今天的主題是:如何優雅的打日志。
3. 如何優雅的打日志
在Java體系中,日志的實現有很多,logback、log4j等等,網上講怎么配置的也非常多,推薦不知道怎么配置的可以看看這篇文章 log4j2 異步日志正確配置
今天我想聊一聊在真正的生產環境中,如何打日志,哪些地方需要打日志,哪些地方不需要打日志,如何優雅的打日志,這可是血與淚的教訓中形成的。
3.1 如何打日志
一個合格的日志必須具備以下要素。具體的時間、日志級別、全局traceId,類名+方法名 + 具體行數 + 具體的內容,尤其是全局traceId,必備。
###|||2025-06-01 17:53:36.000|||INFO|||[全局traceId]()|||http-nio-8080-exec-7|||ClassName|||methodName|||182---> 具體日志內容
3.2 哪些地方需要打日志
- 方法的入口必須打日志。比如controller開頭,controller結尾。當然你也可以使用aop全局打印日志。
- 有分支邏輯之前必須打日志。比如你從阿波羅里面讀取的配置 if (switch) {xxx} ,又比如你整合了所有數據,最后判斷走a邏輯還是b邏輯
- 如果涉及到策略模式、模板模式等設計模式,必須明確打印出,走的是哪個具體的service方法,否則給其他人或者排查問題,會帶來很大的困擾
- 調用RPC前后必須打日志,比如 log.info("req = {}", req), doXXX,log.info(”res = {}“, res),如果如果調用失敗,拋異常,必須把完整的棧鏈路打印出來
- 從數據庫獲取的數據必須打日志。因為數據庫的狀態可能會變,比如客戶的賬號status信息,必須是當時的那個時點的狀態信息,而不是在從數據庫撈數據,是不準確的。
- 重要數據、上下文數據、一些狀態等重要信息必須打日志
- 建議打日志req bo等使用json,比如 log.info("req = {}", JSON.toJsonString(req)),這樣排查問題格式化比較方便
- 有些公司的日志平臺限制長度,比如1000個字符等等,注意長度
- 寧可多打,也不要少打,因為少打日志,對排查問題難度太大了。
4. 最后
剛畢業在第一家公司的時候,由于項目比較大,本地是啟動不了的、不能debug。只能在stg、pre等環境啟動,也就養成了我看日志的習慣,也慢慢鍛煉了我排查問題的水平。
因此也希望大家養成打日志的好習慣,不要自己的代碼被其他人接手的時候,還要被罵這不行那不行的,這樣口碑會非常不好的。
慢慢去補這個項目的日志了。

浙公網安備 33010602011771號