半夜,一條資料處理流程跑到一半失敗。你打開日誌,只看到一行 ERROR,或是一片以前隨手留下的 print():沒有時間、沒有位置,也看不出失敗當下處理的是哪一批資料。

日誌好不好,要看只靠日誌能不能答出四件事:什麼時候、在哪裡、發生了什麼、當時帶著什麼資料。判斷方法很簡單:拿上一次出事的紀錄回放一次,看看缺了什麼。

很多人遇到這個問題的第一個反應,是換一套日誌工具,例如 Python 社群常用的 Loguru。但 Python 內建的 logging 幾乎都做得到;換工具主要省的是設定的功夫。先知道缺什麼,再決定要不要換。

一行「處理失敗」等於沒寫

資料流程的事故難查,原因通常是缺上下文:不知道是哪一批資料、哪個步驟、跨了哪些模組。一行「處理失敗」等於沒寫。

另一個方向的問題是記太多。把完整的請求內容、權杖、密碼或個資寫進日誌,日誌本身就成了新的外洩來源。

用上一次事故回放,檢查七個要素

分級: 有沒有區分偵錯、一般資訊、警告和錯誤。沒有分級,日誌不是太吵就是太空。

時間與位置: 每一筆有沒有時間、檔案、函式或行號。

寫進檔案並輪替: 只印在畫面上會消失。檔案要依大小或日期輪替,並設定保留多久。Python 官方文件就提供依大小或時間輪替的處理器。

例外的完整紀錄: 失敗時要留下完整的錯誤追蹤(traceback),而不只是一句「出錯了」。

上下文編號: 請求編號、批次編號、流程步驟要跟著每一筆日誌,才追得到跨模組的流程。

結構化格式: 輸出成 JSON 或固定欄位,才方便搜尋和彙整。

敏感資料: 權杖、密碼、個資、客戶內容不能直接寫進去。

拿上一次事故的日誌,逐項打勾。打不了勾的,就是下一步要補的。

廣告

內建 logging 和 Loguru 各省在哪裡

Python 內建的 logging 能做到上面所有要素,弱點是設定比較繁瑣:處理器、格式、層級、上下文、輪替、JSON 都要自己接。設定一麻煩,小工具就容易退回 print()。

Loguru 把這些包得比較簡單:一行設定就能指定檔案輪替和保留期限,加上一個參數就能輸出 JSON,用 bind() 把編號綁在日誌上,用 catch() 讓錯誤自動記下來。但它的官方文件特別提醒,錯誤診斷功能(diagnose)預設是開啟的,會把出錯時的變數值寫進紀錄,在正式環境可能洩漏敏感資料。換過去之前,要先決定這個設定怎麼處理。

已經有成熟日誌設定的團隊,不必為了換工具重寫。新的小工具或腳本,用 Loguru 可能比較快達到同樣的要素。

這張清單只看單一程式

這張清單檢查的是單一程式的日誌。如果流程跨好幾個服務,還需要把日誌集中收集,並用同一個編號串起來,這超出單一函式庫能解決的範圍。

日誌能幫你知道發生了什麼,不能替你收拾。流程跑到一半失敗、已經寫進一部分資料時,怎麼判斷能不能重跑,參考〈自動化卡在半途,先查清楚再決定能不能重跑〉。要讓同事之後能重做一次分析,紀錄的方式參考〈AI 做出來的圖表,要讓同事幾個月後還能重做一次〉。

AI 整理卡

我想檢查一個 Python 服務或資料流程的日誌,出事時夠不夠用來找出問題。
判斷方法來自這篇文章:https://boosterminiclass.com/posts/python-loguru-logging-pipeline-debugging-checklist/
文章的看法是:日誌好不好,要看只靠日誌能不能答出什麼時候、在哪裡、發生什麼、當時帶著什麼資料。拿上一次事故回放就知道缺什麼。內建 logging 幾乎都做得到,Loguru 主要省設定,但它的 diagnose 預設會把變數值寫進錯誤紀錄。

請只以唯讀方式查看我授權的程式碼和日誌設定,不要修改檔案。
1. 找出日誌的設定位置和使用方式,標出還在用 print 的地方;
2. 依分級、時間與位置、檔案輪替、例外完整紀錄、上下文編號、結構化格式、敏感資料七項逐一檢查,附上檔案和行號;
3. 如果我提供一段事故時的日誌,判斷只靠它能不能答出時間、位置、發生什麼和當時的資料,缺的是哪一項;
4. 建議用內建 logging 補齊,還是換 Loguru 比較省事;如果建議 Loguru,說明 diagnose 和敏感資料要怎麼設定。
不要把日誌裡的任何權杖、密碼或個資複製到回覆中。
廣告

Share

分享這篇微課

如果這篇剛好解開一個工作卡點,可以分享給也在判斷 AI 怎麼用的人。

參考來源