日誌記錄對於任何軟體系統都是必不可少的。使用日誌,您可以解決各種問題,包括除錯應用程式錯誤、安全缺陷、系統緩慢等。在本文中,我們將討論如何使用自定義屬性有效地使用Python日誌記錄。
Python 日誌記錄
在我們深入研究之前,我想用一個例子簡單地解釋一下基本的 Python 日誌模組。
#!/opt/bb/bin/python3.7
import logging import sys
root = logging.getLogger() root.setLevel(logging.DEBUG) std_out_logger = logging.StreamHandler(sys.stdout) std_out_logger.setLevel(logging.INFO) std_out_formatter = logging.Formatter(<font>"%(levelname)s - %(asctime)s %(message)s") std_out_logger.setFormatter(std_out_formatter) root.addHandler(std_out_logger)
logging.info("I love DDD!")
|
上面的示例在執行時列印以下內容:
INFO - 2024-03-09 19:49:07,734 I love DDD!
在上面的示例中,我們正在建立root記錄器和日誌訊息的記錄格式。在第 6 行,logging.getLogger()如果已建立,則返回記錄器;如果沒有,它會上升到層次結構的上一級並返回父記錄器。我們定義自己的StreamHandler來在控制檯列印日誌訊息。
每當我們記錄訊息時,都必須記錄.LogRecord在第 10 行,我們定義了基本格式,包括級別名稱、字串格式的時間以及實際訊息本身。由此建立的處理程式設定在根記錄器級別。
我們可以使用LogRecord庫中的任何預定義日誌屬性名稱和格式。但是,假設您想要列印一些附加屬性contextId,例如自定義日誌記錄介面卡來救援。
記錄介面卡
class MyLoggingAdapter(logging.LoggerAdapter):
def __init__(self, logger): logging.LoggerAdapter.__init__(self, logger=logger, extra={})
def process(self, msg, kwargs): return msg, kwargs
|
我們建立自己的版本Logging Adapter並將“額外”引數作為格式化程式的字典傳遞。
上下文ID過濾器
import contextvars
class ContextIdFilter(logging.Filter):
context_id = contextvars.ContextVar('context_id', default='')
def filter(self, record): # add a new UUID to the context. req_id = str(uuid.uuid4()) if not self.context_id.get(): self.context_id.set(req_id) record.context_id = self.context_id.get() return True
|
我們建立自己的過濾器來擴充套件logging過濾器,該過濾器返回True是否應記錄指定的日誌記錄。我們只需將我們的引數新增到日誌記錄中並return True始終,從而將我們的唯一引數新增id到記錄中。在上面的示例中,id為每個新上下文生成一個唯一的上下文。對於現有上下文,我們返回contextId已從contextVars.
自定義記錄器
import logging
root = logging.getLogger() root.setLevel(logging.DEBUG) std_out_logger = logging.StreamHandler(sys.stdout) std_out_logger.setLevel(logging.INFO) std_out_formatter = logging.Formatter(<font>"%(levelname)s - %(asctime)s ContextId:%(context_id)s %(message)s") std_out_logger.setFormatter(std_out_formatter) root.addHandler(std_out_logger) root.addFilter(ContextIdFilter())
adapter = MyLoggingAdapter(root)
adapter.info("I love DDD!") adapter.info("this is my custom logger") adapter.info("Exiting the application")
|
現在讓我們將其放在記錄器檔案中。將contextId過濾器新增到root.請注意,我們在需要記錄訊息的地方使用我們自己的介面卡來代替記錄。
執行上面的程式碼會列印以下訊息:
INFO - 2024-04-20 23:54:59,839 ContextId:c10af4e9-6ea4-4cdf-9743-ea24d0febab6 I love DDD! INFO - 2024-04-20 23:54:59,842 ContextId:c10af4e9-6ea4-4cdf-9743-ea24d0febab6 this is my custom logger INFO - 2024-04-20 23:54:59,843 ContextId:c10af4e9-6ea4-4cdf-9743-ea24d0febab6 Exiting the application
|
透過設定root.propagate = False,記錄到此記錄器的事件將被傳遞到更高階別的日誌記錄(也稱為父日誌記錄類)的處理程式。
結論
Python 不提供內建選項來在日誌記錄中新增自定義引數。相反,我們在 Python 根記錄器之上建立一個包裝記錄器並列印我們的自定義引數。這在除錯特定於請求的問題時會很有幫助。