
給還在用
dd()和console.logdebug 的你——來聊聊正經的 Log 設計,讓你半夜被叫起來的時候不會想哭。
先講結論
好的 Log 設計要做到一件事:出事的時候能在五分鐘內還原現場。達到這個目標只需要兩步——設計好 Log 格式,然後用 middleware 自動記錄。
系統監控的兩種路線
你的系統掛了,你怎麼知道?
| 類型 | 做法 | 例子 |
|---|---|---|
| 主動式 | 自己埋 Log,自己看 | 自定義 access log |
| 被動式 | 讓外部工具幫你盯 | Datadog、GCP Stack Driver |
哪個比較好?老實說,兩個都要做。但如果你只能選一個,先做主動式。因為外部工具再厲害,也不知道你的業務邏輯長什麼樣——它能告訴你 response time 變慢了,但不能告訴你是哪個使用者的哪個操作觸發了 bug。
Log 格式怎麼設計?
我用過的格式長這樣:
[{DATETIME}] {APP_ENV}.{LEVEL}: {TYPE} {IP} {TIMESTAMP} {METHOD} {REQUEST_URI} {PAYLOAD} {HEADER} {IDENTIFIER}
看起來很多欄位對吧?但每個都有用:
- DATETIME + TIMESTAMP:兩個時間?對,一個給人看,一個拿來程式篩選
- APP_ENV:staging 和 production 的 Log 混在一起你就知道痛了
- LEVEL:INFO / ERROR / WARNING,查問題的時候直接
grep ERROR - TYPE:標記是 Request 還是 Response,這樣你能看到「進去什麼、出來什麼」
- IDENTIFIER:使用者識別,出事的時候追蹤特定用戶的行為軌跡
掛在 Middleware 上
為什麼用 middleware?因為 Laravel(或 Django)的 middleware 每個 request/response 都會經過。你只要寫一次,所有 API 的 Log 就自動記好了。
不要在每個 Controller 裡面手動寫 Log::info(...)。你會忘記的,我保證。
實戰查詢指令
Log 記了不查等於沒記。以下是我最常用的幾個:
追蹤某個使用者的操作歷程:
grep 1682394555 middleware_access-2023-04-25.log | awk '{print $1" "$2" "$3" "$6" - "$7" - "$8}'用 timestamp 當關鍵字,就能撈出同一時間段的所有 request。
看某支 API 被打了幾次:
grep /api/sale-property/search-meta middleware_access-2023-04-25.log | wc -l發現某支 API 被打了異常多次?可能是前端寫了無限迴圈,也可能是有人在爬你的資料。
統計錯誤次數:
grep ERROR middleware_access-2023-04-25.log | wc -l如果數字突然飆高,恭喜,你有事情要處理了。
做完 Log 之後呢?
Log 只是第一步。接下來你會需要:
- 告警系統:錯誤超過閾值自動通知(不然你得自己盯著看)
- Log 輪轉:決定 Log 檔案多久清一次,不然硬碟會被塞爆
- 串接監控平台:把 Log 接到 Grafana 或 ELK,用圖表看趨勢
我在 Proto 專案裡把 Log 分成四層:request log、response log、error log、query log。四層疊起來,任何一次 API 呼叫的完整過程都能還原。聽起來很搞工,但半夜被叫起來 debug 的時候,你會感謝自己。
Log 寫得好不好,決定了你半夜被 call 的時候是花五分鐘還是五小時。