[後端] Log 不只是用來看錯誤
前言
很多人一開始寫 log,都是在程式壞掉時才想到:
1 | Console.WriteLine("error"); |
或是:
1 | Console.WriteLine(ex.Message); |
這當然比完全沒有 log 好,但如果系統真的在線上環境出問題,這種資訊通常還是不夠。
log 的價值不只是「看到錯誤」,更重要的是幫助我們還原當時發生了什麼事。
Log 要能串起流程
假設使用者回報:「我按送出之後畫面一直失敗。」
如果 log 只有一行:
1 | System error |
那幾乎沒有辦法判斷問題在哪。
比較有幫助的 log,至少要能讓我們串起流程:
1 | Start creating order. userId=123 |
這樣就能看出問題大概發生在付款服務逾時,而不是訂單驗證或資料庫寫入。
Log Level 要分清楚
常見 log level 大概可以這樣理解:
| Level | 使用情境 |
|---|---|
| Debug | 開發或排查細節,正式環境通常不會大量開啟 |
| Info | 系統正常流程中的重要事件 |
| Warning | 發生異常狀況,但系統仍可繼續運作 |
| Error | 功能失敗或需要工程師追查的錯誤 |
| Critical | 系統嚴重異常,可能影響大範圍服務 |
如果全部都用 Error,真正重要的錯誤就會被淹沒。
如果全部都用 Info,正式環境的 log 量可能會太大。
所以 log level 的重點是:讓訊息的重要程度可以被快速判斷。
Log 要放有意義的上下文
只記錄錯誤訊息通常不夠。
例如:
1 | Payment failed |
這句話知道付款失敗,但不知道是哪一筆訂單、哪個使用者、哪個付款管道。
比較好的方式是加上上下文:
1 | Payment failed. userId=123, orderId=456, provider=ExamplePay |
常見可以放進 log 的資訊有:
- user id
- order id
- request id 或 trace id
- 外部服務名稱
- 重要參數,但不包含敏感資訊
這些資訊可以讓我們更快定位問題。
不要把敏感資料寫進 Log
log 很有用,但也很危險。
下面這些內容不應該直接寫進 log:
- 密碼
- token
- 信用卡資訊
- 身分證字號
- 完整個資
- 任何不該被工程師隨意看到的敏感資料
有時候只是為了 debug 方便,順手把整個 request body 印出來,但如果裡面有敏感欄位,就會變成資安風險。
比較好的做法是只記錄必要資訊,敏感欄位遮蔽或完全不記。
錯誤 Log 要保留 Exception
發生 exception 時,不要只記錄 ex.Message。
因為 ex.Message 通常只有一句簡短描述,缺少 stack trace。
比較好的做法是把完整 exception 一起交給 logging 工具處理。
概念上像這樣:
1 | logger.LogError(ex, "Create order failed. userId={UserId}, orderId={OrderId}", userId, orderId); |
這樣 log 裡會同時有錯誤訊息、stack trace,以及我們補上的上下文。
未來排查問題時會省非常多時間。
結語
好的 log 不是越多越好,而是要在出事時提供足夠線索。
我會用這幾個原則檢查:
- 是否能看出流程走到哪一步?
- 是否有足夠上下文定位問題?
- log level 是否合理?
- 是否避免記錄敏感資訊?
- exception 是否保留完整 stack trace?
平常寫 log 多花一點心思,線上出問題時就少一點痛苦。
如果您喜歡我寫的文章,幫我按個5下讚吧!感謝您的鼓勵和支持!