Python logging 日誌模組完整教學:從基礎到進階配置一次搞懂
為什麼不該用 print 除錯?
我相信每個寫 Python 的人都經歷過這個階段——程式出了問題,第一反應就是到處塞 print()。老實說,我自己也這樣幹了好一陣子,直到有一天接手了一個線上專案,裡面散落著上百個 print,完全搞不清楚哪個是除錯用的、哪個是正式輸出。那時候我才真正理解為什麼 Python 內建的 logging 模組這麼重要。
logging 模組最大的優勢在於:你可以控制訊息的嚴重程度、輸出目的地、格式,甚至可以在不改動程式碼的情況下調整日誌行為。這在團隊開發和正式環境中是不可或缺的。如果你之前寫過 Python 裝飾器,你會發現 logging 跟裝飾器搭配起來特別好用,可以輕鬆實現函數呼叫的自動紀錄。
logging 模組基礎入門
Python 的 logging 模組是標準函式庫的一部分,不需要額外安裝。最簡單的用法只需要兩行:
import logging
logging.warning('這是一個警告訊息')
執行後你會在終端機看到:
WARNING:root:這是一個警告訊息
這裡有幾個重點:預設只會顯示 WARNING 以上的訊息,所以如果你用 logging.info() 或 logging.debug(),預設是看不到的。另外,root 代表的是根 logger 的名稱。
五大日誌等級詳解
logging 定義了五個標準的日誌等級,從低到高分別是:
- DEBUG (10):最詳細的資訊,通常用在開發階段追蹤程式流程
- INFO (20):一般資訊,確認程式按預期運作
- WARNING (30):警告訊息,程式還能運作但有潛在問題
- ERROR (40):錯誤訊息,某些功能已經無法正常執行
- CRITICAL (50):嚴重錯誤,程式可能無法繼續運行
實務上最常用的是 INFO 和 WARNING。我自己的習慣是:開發時設定成 DEBUG 看所有細節,部署到正式環境就調成 WARNING,這樣就不會被大量的 debug 訊息淹沒。
basicConfig 快速設定
logging.basicConfig() 是最快配置 logging 的方式。你可以設定日誌等級、輸出格式、輸出檔案等:
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='app.log',
filemode='w'
)
logging.debug('Debug 訊息')
logging.info('程式啟動')
logging.warning('記憶體使用率偏高')
logging.error('資料庫連線失敗')
logging.critical('系統崩潰')
要注意的是,basicConfig 只能呼叫一次,而且必須在任何 logging 呼叫之前。如果你先呼叫了 logging.warning(),之後再呼叫 basicConfig 就不會生效了。這是很多初學者會踩到的坑。
Handler 處理器完整介紹
Handler 決定了日誌訊息的「去處」。logging 模組提供了好幾種 Handler:
StreamHandler
將日誌輸出到終端機(stdout 或 stderr):
import logging
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
logger.addHandler(stream_handler)
logger.info('這會印在終端機上')
FileHandler
把日誌寫到檔案裡。這在正式環境特別實用:
file_handler = logging.FileHandler('app.log', encoding='utf-8')
file_handler.setLevel(logging.WARNING)
logger.addHandler(file_handler)
小提醒:如果你的日誌包含中文,記得加上 encoding='utf-8',不然可能會遇到編碼問題。
同時輸出到多個目的地
你完全可以同時加多個 Handler。比如開發時我會設定 DEBUG 等級輸出到終端機,WARNING 以上同時寫到檔案:
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)
# 終端機看所有訊息
stream_h = logging.StreamHandler()
stream_h.setLevel(logging.DEBUG)
# 檔案只記錄警告以上
file_h = logging.FileHandler('errors.log', encoding='utf-8')
file_h.setLevel(logging.WARNING)
logger.addHandler(stream_h)
logger.addHandler(file_h)
Formatter 格式化輸出
Formatter 讓你自訂日誌的輸出格式。常用的格式化變數有:
%(asctime)s:時間戳記%(name)s:logger 名稱%(levelname)s:日誌等級%(message)s:日誌訊息%(filename)s:檔案名稱%(lineno)d:行號
formatter = logging.Formatter(
'%(asctime)s | %(name)-12s | %(levelname)-8s | %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
stream_handler.setFormatter(formatter)
格式化做得好,日誌就像一本結構清楚的帳本,出問題時可以快速定位。
Logger 階層架構
logging 模組的 Logger 有階層關係,跟 Python 的套件結構很像。比如 my_app.db 是 my_app 的子 logger:
parent_logger = logging.getLogger('my_app')
child_logger = logging.getLogger('my_app.db')
child_logger2 = logging.getLogger('my_app.api')
子 logger 的訊息會自動向上傳播到父 logger。這代表你只需要在父 logger 設定 Handler,所有子 logger 的訊息都會被處理。如果你不想要這個行為,可以設定 logger.propagate = False。
這個架構在大型專案中非常好用。如果你在建構 FastAPI REST API,每個路由模組可以有自己的 logger,讓除錯更精準。
進階:RotatingFileHandler 日誌輪替
在正式環境中,日誌檔案會不斷增長。RotatingFileHandler 可以自動管理檔案大小:
from logging.handlers import RotatingFileHandler
rotating_handler = RotatingFileHandler(
'app.log',
maxBytes=5*1024*1024, # 5MB
backupCount=5,
encoding='utf-8'
)
logger.addHandler(rotating_handler)
當 app.log 超過 5MB 時,它會自動改名成 app.log.1,新的日誌繼續寫到 app.log。最多保留 5 個備份檔案。
另外還有 TimedRotatingFileHandler,可以按時間輪替,每天午夜自動建立新的日誌檔案,保留最近 30 天的紀錄。
實務最佳實踐
分享幾個我這幾年累積的 logging 最佳實踐:
- 用
__name__作為 logger 名稱:logger = logging.getLogger(__name__),這樣 logger 名稱會自動對應模組路徑 - 不要在函式庫中呼叫 basicConfig:讓使用者自己決定如何配置
- 善用
logger.exception():在 except 區塊中使用,它會自動附加 traceback 資訊 - 用 % 格式化而非 f-string:
logger.info('使用者 %s 登入', username)更有效率 - 分離不同環境的配置:開發用 DEBUG + StreamHandler,正式用 WARNING + RotatingFileHandler
如果你的專案有用到非同步程式設計,logging 在 async 環境中也能正常使用,但要注意 FileHandler 的寫入是同步的。
結語
從 print 到 logging,看起來只是換了一個函數,但背後代表的是從「業餘開發」到「專業工程」的思維轉變。建議你現在就打開手邊的專案,把那些散落的 print 換成 logging 吧。從 basicConfig 開始,等熟悉了再慢慢加上 Handler、Formatter 和日誌輪替。相信我,未來的你會感謝現在的你。
繼續閱讀
Python Requests 網頁爬蟲入門:從 HTTP 請求到資料擷取完整教學
想用 Python 自動抓取網頁資料?這篇手把手教你用 Requests + BeautifulSoup 建立你的第一支爬蟲程式。
相關文章
你可能也喜歡
探索其他領域的精選好文