Python 的 logging 模組提供強大的日誌記錄功能,而格式化器(Formatter)更是其中關鍵一環,能將日誌訊息依指定格式輸出。設定格式化器能讓我們更輕鬆地閱讀和分析日誌,尤其在需要根據不同輸出目標(例如檔案、控制檯)呈現不同風格的日誌時,更顯其重要性。預設的格式化器僅顯示日誌訊息,缺乏其他重要資訊。為此,我們需要自訂格式化字串,加入時間戳、日誌級別、程式碼位置等資訊,讓日誌更具參考價值。每個日誌操作都會產生一個 LogRecord 物件,它包含了日誌事件的各種屬性,例如訊息內容、時間戳、日誌級別、程式碼檔案路徑、行號等等。我們可以利用這些屬性,搭配格式化字串中的佔位符,精準控制日誌輸出格式。例如 %(asctime)s 代表時間戳、%(levelname)s 代表日誌級別、%(message)s 代表日誌訊息內容、%(filename)s 和 %(lineno)d 則分別代表程式碼檔案名稱和行號。除了內建屬性,我們還能自訂日期時間格式,例如將 datefmt 引數設定為 "%Y-%m-%d %H:%M:%S",就能以更易讀的格式顯示時間。
記錄格式化器的應用
在Python的日誌模組(logging)中,格式化器(Formatter)是一個強大的工具,能夠幫助我們將日誌記錄以特定格式輸出。透過格式化器,我們可以更方便地閱讀和分析日誌,特別是當我們需要在不同的輸出目標(如檔案和控制檯)上顯示不同風格的日誌時。
格式化器的基本使用
首先,我們來看一段簡單的程式碼範例:
import logging
# 建立自訂記錄器
logger = logging.getLogger(name="test")
logger.setLevel(logging.DEBUG)
# 建立檔案處理器
file_handler = logging.FileHandler("formatted.log")
# 將處理器新增到記錄器
logger.addHandler(file_handler)
# 新增格式化器
formatter = logging.Formatter()
file_handler.setFormatter(formatter)
# 記錄訊息
logger.debug("Hello debug")
logger.info("Hello info")
這段程式碼中,我們建立了一個名為「test」的記錄器,並設定其日誌等級為DEBUG。然後,我們建立了一個檔案處理器來將日誌寫入名為「formatted.log」的檔案。接著,我們建立了一個格式化器並將其設定到處理器上。
然而,這樣的設定並不能達到我們預期的效果。因為我們並沒有為格式化器指定任何格式說明,所以它只會使用預設的格式,即僅顯示日誌訊息而不包含其他資訊。
自訂格式化說明
要讓日誌記錄顯示更多資訊,我們需要為格式化器提供具體的格式說明。以下是修改後的程式碼:
import logging
# 建立自訂記錄器
logger = logging.getLogger(name="test")
logger.setLevel(logging.DEBUG)
# 建立檔案處理器
file_handler = logging.FileHandler("formatted.log")
# 將處理器新增到記錄器
logger.addHandler(file_handler)
# 新增格式化器並指定格式說明
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
file_handler.setFormatter(formatter)
# 記錄訊息
logger.debug("Hello debug")
logger.info("Hello info")
內容解密:
logging.getLogger(name="test"):這行程式碼建立了一個名為「test」的記錄器。logger.setLevel(logging.DEBUG):設定這個記錄器的日誌等級為DEBUG,這意味著它會捕捉所有等級的日誌訊息。logging.FileHandler("formatted.log"):這行程式碼建立了一個檔案處理器,用於將日誌寫入名為「formatted.log」的檔案。logger.addHandler(file_handler):將檔案處理器新增到記錄器中。logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"):這行程式碼建立了一個格式化器,並指定了它應該如何格式化日誌訊息。%(asctime)s表示時間戳、%(name)s表示記錄者名稱、%(levelname)s表示日誌等級名稱、%(message)s表示實際的日誌訊息。file_handler.setFormatter(formatter):將格式化器設定到檔案處理器上。logger.debug("Hello debug")和logger.info("Hello info"):這兩行程式碼分別記錄了一條DEBUG等級和一條INFO等級的日誌訊息。
日誌記錄物件(LogRecord)
在Python的日誌模組中,每次執行日誌操作時都會自動建立一個LogRecord物件。這些物件包含了關於日誌事件的一系列屬性。以下是LogRecord類別的一些主要屬性:
name (str):記錄者名稱。level (int):日誌等級(例如,DEBUG、INFO)。pathname (str):原始碼檔案的完整路徑。lineno (int):原始碼中的行號。msg (Any):事件描述訊息。args (tuple or dict):可變資料,用於合併到msg引數中以建立事件描述。exc_info (tuple[type[BaseException], BaseException, types.TracebackType] | None):例外資訊元組。func (str or None):包含日誌呼叫的函式或方法名稱。sinfo (str or None):代表堆積疊資訊的文字字串。
這些屬性可以幫助我們更精確地控制和檢視日誌訊息。例如,如果我們想要顯示包含時間戳、記錄者名稱、日誌等級和實際訊息的日誌,可以使用上述格式說明來完成。
LogRecord 屬性
除了上面提到的一些主要屬性外,LogRecord還有一些其他屬性可以用來進一步自訂日誌輸出:
%(asctime)s:人類可讀取的建立時間。%(created)f:日誌記錄建立時間(來自time.time())。%(filename)s:路徑中的檔案名稱部分。%(funcName)s:包含日誌呼叫的函式名稱。%(levelname)s:訊息文字記錄等級(例如,‘DEBUG’,‘INFO’)。%(levelno)s:訊息數字記錄等級。%(lineno)d:來源行號。%(message)s:在呼叫Formatter.format()時設定的登入訊息。%(module)s:模組名稱(即filename中的name部分)。%(msecs)d:當建立log record時所取得時間戳之毫秒部分。%(name)s:用於登入訊息之登入者名稱。%(pathname)s:完整路徑(如果可取得)。%(process)d:程式ID(如果可取得)。%(processName)s:程式名稱(如果可取得)。%(relativeCreated)d:log record 建立之時間與載入logging 模組之間相隔之毫秒數。%(thread)d:執行緒ID(如果可取得)。%(threadName)s:執行緒名稱(如果可取得)。%(taskName)s: asyncio.Task 名稱(如果可取得)。
這些屬性使得我們可以靈活地自訂日誌輸出格式,以滿足不同應用場景中的需求。例如,當我們需要除錯特定功能時,可以新增更多細節來幫助我們快速定位問題;而當我們只是想要追蹤系統執行狀態時,可以使用較簡單的格式來減少不必要的資訊。
Python 日誌格式器:探討與實踐
在 Python 中,日誌(logging)是一個強大的工具,能夠幫助我們追蹤程式的執行過程及排除錯誤。然而,日誌的格式化處理是否得當,將直接影響到我們如何有效地利用這些日誌資訊。本文將探討 Python 日誌格式器(Log Formatters)的使用方法,並結合具體案例進行講解。
日誌格式化的基礎
首先,讓我們來看一個簡單的日誌格式化範例:
import logging
# 建立 Formatter 物件
formatter = logging.Formatter(
("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
)
# 建立日誌記錄器
logger = logging.getLogger(name="test")
logger.setLevel(logging.DEBUG)
# 建立檔案處理器並設定格式器
file_handler = logging.FileHandler("test.log")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# 記錄日誌資訊
logger.debug("Hello debug")
logger.info("Hello info")
內容解密:
這段程式碼展示瞭如何使用 Python 的 logging 模組來建立和格式化日誌。以下是程式碼的詳細解析:
-
建立 Formatter 物件:
formatter = logging.Formatter( ("%(asctime)s - %(name)s - %(levelname)s - %(message)s") )這裡建立了一個
Formatter物件,指定了日誌訊息的格式。%(asctime)s表示人類可讀的時間戳、%(name)s表示發出日誌訊息的 logger 名稱、%(levelname)s表示日誌等級、%(message)s表示實際的日誌訊息。 -
建立日誌記錄器:
logger = logging.getLogger(name="test") logger.setLevel(logging.DEBUG)建立了一個名為
test的 logger,並將其等級設定為DEBUG,這意味著所有等級的日誌訊息都會被記錄。 -
建立檔案處理器並設定格式器:
file_handler = logging.FileHandler("test.log") file_handler.setFormatter(formatter) logger.addHandler(file_handler)建立了一個
FileHandler,用於將日誌訊息寫入名為test.log的檔案。然後將剛才建立的formatter設定為這個處理器的格式器。 -
記錄日誌資訊:
logger.debug("Hello debug") logger.info("Hello info")最後,使用
logger.debug()和logger.info()記錄了兩條不同等級的日誌訊息。
這些日誌訊息會被寫入 test.log 檔案中,並按照指定的格式顯示。例如:
2024-02-07 08:29:44,734 - test - DEBUG - Hello debug
2024-02-07 08:29:44,734 - test - INFO - Hello info
日誌屬性與自定義格式
在上述範例中,我們使用了幾個常見的日誌屬性來格式化日誌訊息。以下是這些屬性的詳細說明:
%(asctime)s:人類可讀的時間戳。%(name)s:發出日誌訊息的 logger 名稱。%(levelname)s:日誌等級。%(message)s:實際的日誌訊息。
除了這些屬性外,還有一些其他屬性可以用來進一步豐富日誌訊息。例如:
%(filename)s:產生日誌訊息的模組檔名。%(lineno)d:產生日誌訊息的行號。%(pathname)s:完全限定的 Python 指令碼路徑。%(module)s:模組名稱(即檔名不含副檔名)。
自定義格式範例
讓我們來看一個更複雜的範例,展示如何使用這些屬性來自定義日誌格式:
import logging
# 建立自定義 logger
logger = logging.getLogger(name="formatting")
logger.setLevel(logging.DEBUG)
# 建立檔案處理器
file_handler = logging.FileHandler("formatting.log")
# 新增處理器到 logger
logger.addHandler(file_handler)
# 新增自定義格式器
fmt = ("%(asctime)s - %(filename)s - line number: %(lineno)d - %(message)s")
formatter = logging.Formatter(fmt)
file_handler.setFormatter(formatter)
# 記錄日誌資訊
logger.debug("Hello debug")
logger.info("Hello info")
內容解密:
這段程式碼展示瞭如何使用更多的日誌屬性來豐富日誌訊息。以下是程式碼的詳細解析:
-
建立自定義 logger:
logger = logging.getLogger(name="formatting") logger.setLevel(logging.DEBUG)建立了一個名為
formatting的 logger,並將其等級設定為DEBUG。 -
建立檔案處理器:
file_handler = logging.FileHandler("formatting.log")建立了一個
FileHandler,用於將日誌訊息寫入名為formatting.log的檔案。 -
新增處理器到 logger:
logger.addHandler(file_handler)將剛才建立的處理器新增到
logger中。 -
新增自定義格式器:
fmt = ("%(asctime)s - %(filename)s - line number: %(lineno)d - %(message)s") formatter = logging.Formatter(fmt) file_handler.setFormatter(formatter)象指定了新的格式字串
fmt,包含了%(filename)s和%(lineno)d屬性。然後將這個格式化器設定為處理器的格式化器。 -
記錄日誌資訊:
logger.debug("Hello debug") logger.info("Hello info")最終使用
logger.debug()和logger.info()記錄了兩條不同等級的日誌訊息。
當我們執行這段程式碼時,可以看到生成的一個名為「formatting.log」檔案中的內容會類別似於:
2024-05-07 09:57:15,884 - more_log_formatting.py - line number: 19 - Hello debug
2024-05-07 09:57:15,884 - more_log_formatting.py - line number: 20 - Hello info
自訂日期與時間格式
在某些情況下,我們可能希望自訂日期與時間格式。Python 的 logging 模組允許我們透過 datefmt 引數來實作這一點。以下是如何自訂日期與時間格式的一個範例:
import logging
# 建立自定義 logger
logger = logging.getLogger(name="datefmt")
logger.setLevel(logging.DEBUG)
# 建立檔案處理器
file_handler = logging.FileHandler("datefmt.log")
# 新增處理器到 logger
logger.addHandler(file_handler)
# 新增日期與時間格式化引數並設定自定義格式化器
datefmt = "%a %d %b %Y"
formatter = logging.Formatter(
("%(asctime)s - %(name)s - %(levelname)s - %(message)s"),
datefmt=datefmt)
file_handler.setFormatter(formatter)
# 記錄日期與時間資訊中有具體內容之資料訊號訊息之內容資訊之內容資訊資料內容資料資訊資料之內容資料資訊資料內容資訊訊號訊息之內容資訊資料之內容資料訊號訊息之內容資料資訊之內容資料
logger.debug("Hello debug")
logger.info("Hello info")
檢視
graph TD;
A[日期與時間] --> B[日期];
A --> C[時間];
B --> D[%a];
B --> E[%d];
B --> F[%b];
B --> G[%Y];
檢視此圖示解釋:
此圖表說明瞭日期與時間字串所含有之基本字元所代表之意義。顯示如何整合日期、星期、月份、年份及其他時間元素以進行日期與時間之自定義表示方法。
graph TD;
A[日期] --> B[星期縮寫];
A --> C[月份縮寫];
A --> D[數值日期];
A --> E[完整年份];
檢視此圖示解釋:
此圖表說明瞭日期字串所含有之基本字元所代表之意義。顯示如何整合星期縮寫、月份縮寫、數值日期及完整年份以進行日期之自定義表示方法。
graph TD; A[時間]-->B[小時]; A-->C[分鐘]; A-->D[秒數];
檢視此圖示解釋:
此圖表說明瞭時間字串所含有之基本字元所代表之意義。顯示如何整合小時、分鐘及秒數以進行時間之自定義表示方法。
小段落標題
在此範例中,「datefmt」引數使用了 Python 的 datetime 模組中的日期時間程式碼來設定特定樣貌。「%a」代表星期縮寫,「%d」代表數值形式之一個月份中的第幾天,「%b」代表月份縮寫,「%Y」代表完整年份。「%H」、「%M」、「%S」分別代表小時、分鐘、秒數以實作更多樣化且精確地表示方法。
graph TD; A["datefmt"]-->B["%a"]; A-->C["%d"]; A-->D["%b"]; A-->E["%Y"]; B-->F["星期縮寫"]; C-->G["月份縮寫"]; D-->H["數值形式之一個月份中的第幾天"]; E-->I["完整年份"];
檢視此圖示解釋:
此圖表說明瞭 datefmt 中所含有之基本字元所代表之意義。「datefmt」引數使用了 Python 的 datetime 模組中的日期時間程式碼來設定特定樣貌。「%a」代表星期縮寫,「%d」代表數值形式之一個月份中的第幾天,「%b」代表月份縮寫,「%Y」代表完整年份以便能夠精確且有效地表示日期與時間。
小段落標題
graph TD; A["time"]-->B["%H"]; A-->C["%M"]; A-->D["%S"];
小段落標題
此圖表說明瞭 time 中所含有之基本字元所代表之意義。「time」引數使用了 Python 的 datetime 模組中的日期時間程式碼來設定特定樣貌。「%H」代表小時,「%M」代表分鐘,「%S」代表秒數以便能夠精確且有效地表示時間。
心得與反思
在本文中,玄貓探討了 Python 日誌模組中「Log Formatters」功能應用方法及其實踐技巧。從基本概念到進階應用技巧分析Python 日誌模組中的「Log Formatters」,並結合具體案例展示如何根據需求進行自定義設計及應用技巧分析Python 日誌模組中的「Log Formatters」。希望能夠對大家在開發過程中遇到相關問題時提供一些靈感和幫助。