Python-Logging模組介紹

開發者的記錄事件工具

Jacy Chu
9 min readNov 6, 2023

參考資料:
1. Python Logging 模組
2. Python Logging 模組進階篇 — logger與自動備份

軟體執行時,追蹤有什麼事件發生的動作稱為 Logging。軟體開發者會使用 Logging 這樣的機制是因為想知道在運行過程中是否有特定的事件發生。

重要程度(level)

開發者也可以指派事件的重要程度(level)。

節錄自python 3.12官方文件

預設的等級是WARNING,意味著只會追蹤該等級及以上的事件,除非更改日誌配置。若把等級改成DEBUG,所有資訊都將被列印。

可以藉由basicConfig做設定。

logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG)

filename 輸出的檔案名稱跟位置,可以寫成'logs/example.log'。這樣會在logs資料夾中生成example.log 檔案。

filemode 預設為 'a' ,代表append。執行,會把新輸出的log印在接續之前輸出的部分。若改成'w' ,代表write,會把原本輸出的內容蓋掉。

記錄變數資料

若要記錄變數數據,請使用格式字串作為事件描述訊息,並附加傳入變數資料作為參數。例如:

import logging
logging.warning('%s before you %s', 'Look', 'leap!')

將顯示:

WARNING:root:Look before you leap!

datefmt參數的格式與time.strftime()支援的格式相同。

實作記錄

新增一個資料夾,並在其中加入一個test.py檔案
加入下方內容:

import logging

logging.basicConfig(level=logging.DEBUG, filename='demolog.log', filemode='a', format='%(asctime)s - %(levelname)s : %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')

logging.info('info')
logging.debug('debug')
logging.warning('warning')
logging.error('error')
logging.critical('critical')

按下右上方的執行按鈕

可以看到新生成demolog.log檔案

進階介紹

記錄器

Logger是Logging提供的模組化操作,可以讓你新增刪除Handler。

logger = logging.getLogger()

在括弧中沒有填任何參數表示建立名為 rootLogger

logger = logging.getLogger(__name__)

__name__ 會抓模組名稱為Logger命名。

Logger 的名稱符合句點分隔的階級制度 (period-separated hierarchy) ,也就是名稱用點來分隔,就能夠讓底層模組的 Logger 往上追朔繼承。

舉例:

logger = logging.getLogger("foo")
logger = logging.getLogger("foo.bar")

處理器

Handler物件負責將適當的日誌訊息(基於日誌訊息的嚴重性)分派給處理器的指定目標。Handler包含很多,此篇主要介紹StreamHandlerFileHandler

格式器

格式化器物件配置日誌訊息的最終順序、結構和內容。

style'%','{''$’之一。如果未指定其中之一,則將使用'%'

實作記錄

# create logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# create console handler and file handler set level to debug
ch = logging.StreamHandler()
fh = logging.FileHandler('filehandler.log')

ch.setLevel(logging.DEBUG)

# create formatter
StreamHandlerformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
FileHandlerformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# add formatter to ch
ch.setFormatter(StreamHandlerformatter)

# add formatter to fh
fh.setFormatter(FileHandlerformatter)

logger.addHandler(ch)
logger.addHandler(fh)

logger.info('info')
logger.debug('debug')
logger.warning('warning')
logger.error('error')
logger.critical('critical')

console區可以看到console handler(StreamHandler)印出的內容,另外FileHandler生成一個filehandler.log檔案。

格式補充:

'{''$’ 範例如下:

格式字串補充:

最早的方式是使用「 」符號來設定格式字串。

Python 3 引進 .format() 的語法

Python3.6以後:f-string

f-String在使用上較format()簡便,其開頭是 f,花括號「 { } 」裡面放入參數名稱,字串則使用雙引號( “ ” )標註。

原本

'%(asctime)s - %(name)s - %(levelname)s - %(message)s'

改成

f"%(asctime)s %(name)s %(levelname)s %(message)s"

有關格式字串,可以參考這篇:
🔍Python的字串格式語法.format()與f-string

log 循環覆蓋

開始使用log後,如果一直寫入Log而沒有清除,檔案遲早會占滿硬碟,因此限制檔案大小,及備份,若超過指定數量則會自動刪除最舊的log。

RotatingFileHandler,其中以下的maxBytes即是每個log檔案的大小上限,backupCount則是會備份Log的數量。

import logging.handlers

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
rh = logging.handlers.RotatingFileHandler('rotatingfile', maxBytes=200, backupCount=2)
rh.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(threadName)s', datefmt='%m/%d/%Y %I:%M:%S %p'))
logger.addHandler(rh)

按下執行發現多了兩個檔案一個為rotatingfile,一個為rotatingfile.1。

在生成的過程,會先生出rotatingfile檔案,由於有將maxBytes 設定成 200bytes,所以當打印內容超過時,正要超過 rotatingfile大小時,原本的rotatingfile會變成rotatingfile.1,再生成一個rotatingfile空的檔案去裝剩下的內容。

backupCount是指除了rotatingfile,最多額外生成檔案的數量。像這邊設定成2,代表最多就是rotatingfile, rotatingfile.1, rotatingfile.2這三個檔案。

另一情境,假設rotatingfile.2滿的狀態,而當打印內容超過時,正要超過 rotatingfile大小時,原本的rotatingfile.2會被移除,原本的rotatingfile.1變成rotatingfile.2,原本的rotatingfile變成rotatingfile.1,再生成一個rotatingfile空的檔案去裝剩下的內容。

有關Config的 dictConfig設定,可以參考這篇:
🔍 使用 Python 的 logging 模組記錄程式執行過程

--

--