本文詳細解析了Python的logging模組,從基本介紹到實際應用和最佳實踐。我們通過具體的程式碼範例解釋瞭如何高效地使用這個模組進行紀錄檔記錄,以及如何避免常見的陷阱,旨在幫助讀者更好地掌握這個強大的工具。
在開發過程中,為了記錄應用程式的執行情況,通常我們會採用列印紀錄檔的方式,這種方式不僅可以幫助我們瞭解軟體系統的執行狀態,還可以在系統出現錯誤時,幫助我們快速定位問題。
例如,假設你有以下一段程式碼,它只是簡單地輸出一些資訊:
print("This is some information.")
輸出:
This is some information.
但是,如果我們需要記錄更復雜的資訊,如錯誤資訊、警告或者其他重要的執行時資訊,僅僅使用print就顯得力不從心。這就是我們需要紀錄檔模組的地方。
Python內建的logging模組為我們提供了一套完整的紀錄檔記錄解決方案。在許多情況下,你可能希望你的應用程式能夠在執行時輸出某種形式的狀態資訊,特別是當應用程式需要處理長時間執行的任務,或者當你面臨需要診斷的問題時,logging模組便是你的得力助手。
logging模組可以幫助我們捕獲、處理和記錄紀錄檔資訊,使得我們可以在程式執行的任何地方快速記錄紀錄檔資訊。相比於簡單的print函數,它更具有靈活性,能夠同時輸出紀錄檔到多個地方,如:控制檯、檔案、HTTP GET/POST,SMTP,Socket等,並且可以獨立設定每個輸出的紀錄檔等級。
以下是一個簡單的例子來說明如何使用logging模組:
import logging
# Create a logger and set the log level to INFO
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# Add a StreamHandler to send log messages to console
console_handler = logging.StreamHandler()
logger.addHandler(console_handler)
# Log an informational message
logger.info("This is an informational message.")
這段程式碼會輸出以下資訊到控制檯:
This is an informational message.
logging模組主要由以下幾個部分組成:
Logger: 用於提供應用程式直接使用的介面。
Handler: 將(logger產生的)紀錄檔記錄傳送到合適的目的輸出。
Filter: 提供了更精細的工具來決定輸出哪些紀錄檔記錄。
Formatter: 指定紀錄檔記錄的最終輸出格式。
使用Python的logging模組相當簡單,下面是一個基本的例子,說明如何建立一個紀錄檔並輸出到控制檯。
import logging
# This will log the message to the console
logging.warning('This is a warning message')
這段程式碼將輸出以下警告資訊:
WARNING:root:This is a warning message
在logging模組中,我們有5個級別來描述紀錄檔的重要性。這些級別分別是:
DEBUG:詳細資訊,通常僅在診斷問題時使用。
INFO:確認事情按預期進行。
WARNING:出現了一些預期之外的事情,或者在不久的將來可能出現問題(例如,「磁碟空間不足」)。但是軟體仍在正常工作。
ERROR:由於更嚴重的問題,軟體不能執行某些功能。
CRITICAL:嚴重的錯誤,表明程式本身可能無法繼續執行。
預設情況下,logging模組將紀錄檔記錄到控制檯,並且只處理級別為WARNING以上的紀錄檔。
這一部分我們將會詳解Loggers、Handlers和Formatters這三個主要元件。
Logger是一個紀錄檔物件,主要任務就是記錄紀錄檔。在應用程式程式碼中任何需要紀錄檔的地方,都可以建立一個logger範例,並用其記錄需要的資訊。下面是一個簡單的使用logger的例子:
import logging
# Create a logger
logger = logging.getLogger(__name__)
# Log some messages
logger.debug("This is a debug message.")
logger.info("This is an informational message.")
logger.warning("Careful! Something does not look right.")
logger.error("You have encountered an error.")
logger.critical("The program cannot recover from this situation!")
注意:當我們執行這段程式碼時,我們並沒有看到任何輸出。這是因為預設情況下,logger的級別設定為WARNING,因此只有級別為WARNING以上的紀錄檔會被處理。
Handler物件負責傳送紀錄檔記錄到合適的目的地。不同的handler可以將紀錄檔傳送到控制檯,檔案,郵件,甚至HTTP POST引數等。下面是一個簡單的例子,說明如何使用handler將紀錄檔記錄到檔案和控制檯:
import logging
# Create a logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Create a file handler
file_handler = logging.FileHandler('my_log.log')
logger.addHandler(file_handler)
# Create a console handler
console_handler = logging.StreamHandler()
logger.addHandler(console_handler)
# Log some messages
logger.debug("This is a debug message.")
logger.info("This is an informational message.")
logger.warning("Careful! Something does not look right.")
logger.error("You have encountered an error.")
logger.critical("The program cannot recover from this situation!")
Formatter物件指定紀錄檔記錄的最終順序,結構和內容。你可以自定義紀錄檔資訊的格式,使得紀錄檔資訊更具有可讀性。下面是一個如何使用formatter的例子:
import logging
# Create a logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Create a console handler
console_handler = logging.StreamHandler()
# Create a formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# Add the formatter to the console handler
console_handler.setFormatter(formatter)
# Add the console handler to the logger
logger.addHandler(console_handler)
# Log some messages
logger.debug("This is a debug message.")
logger.info("This is an informational message.")
logger.warning("Careful! Something does not look right.")
logger.error("You have encountered an error.")
logger.critical("The program cannot recover from this situation!")
在Python程式設計中,經常需要捕獲和處理異常。這時,使用logging模組記錄異常資訊會非常方便。在logging模組中,我們可以使用exception()方法記錄異常堆疊資訊。如下例所示:
import logging
logger = logging.getLogger(__name__)
try:
a = [1, 2, 3]
value = a[3]
except IndexError as e:
logger.error("Unhandled exception", exc_info=True)
```
當執行此段程式碼,紀錄檔記錄器將記錄下出現的異常資訊,如下:
```python
ERROR:__main__:Unhandled exception
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
IndexError: list index out of range
當我們的應用程式執行很長時間,併產生大量的紀錄檔時,所有的紀錄檔都寫入一個檔案可能會導致這個紀錄檔檔案過大。這時,我們可以使用RotatingFileHandler來進行紀錄檔卷動。當達到一定的大小或者一定的時間,RotatingFileHandler會自動備份當前紀錄檔檔案,並建立一個新的紀錄檔檔案繼續寫入。如下例所示:
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# Create a file handler
handler = RotatingFileHandler('my_log.log', maxBytes=2000, backupCount=10)
logger.addHandler(handler)
# Log some messages
for _ in range(10000):
logger.info("Hello, world!")
```
這段程式碼將在紀錄檔檔案大小達到2000位元組時建立一個新的紀錄檔檔案,並保留最新的10個紀錄檔檔案。
## 設定紀錄檔級別
根據我們的需要,可以在執行時改變紀錄檔的級別。例如,當我們在偵錯應用程式時,我們可能需要輸出所有級別的紀錄檔。但是在生產環境中,我們可能只關心錯誤及以上級別的紀錄檔。我們可以通過setLevel()函數來改變紀錄檔級別。如下例所示:
```python
import logging
# Create a logger
logger = logging.getLogger(__name__)
# Set log level to DEBUG
logger.setLevel(logging.DEBUG)
# Log some messages
logger.debug("This is a debug message.")
logger.info("This is an informational message.")
logger.warning("Careful! Something does not look right.")
logger.error("You have encountered an error.")
logger.critical("The program cannot recover from this situation!")
在Python中,__name__變數是一個內建變數,它代表當前模組的名稱。當我們在每個模組級別上建立logger並使用__name__作為名稱,我們可以輕鬆地追蹤紀錄檔記錄發生在哪個模組。
import logging
# Create a logger at the module level
logger = logging.getLogger(__name__)
不同的紀錄檔級別表示了不同的嚴重性。正確地使用紀錄檔級別可以幫助我們在大量的紀錄檔中找到我們關心的資訊。一般來說,對於非常嚴重的錯誤,我們應使用CRITICAL或ERROR;對於警告資訊,我們應使用WARNING;對於常規的執行資訊,我們應使用INFO;對於偵錯資訊,我們應使用DEBUG。
當我們的應用程式有大量的紀錄檔時,我們可能希望以一種可解析的方式記錄紀錄檔訊息。例如,我們可以使用JSON格式記錄紀錄檔。這樣,我們就可以使用各種紀錄檔分析工具分析紀錄檔。
import logging
import json
# Create a logger
logger = logging.getLogger(__name__)
# Log a structured message
logger.info(json.dumps({
'action': 'User login',
'username': 'user123',
'ip_address': '123.123.123.123',
'status': 'success',
}))
當捕獲到異常時,我們應使用logger.exception(),這樣就可以在紀錄檔中記錄下完整的異常堆疊資訊。
import logging
logger = logging.getLogger(__name__)
try:
x = 1 / 0
except ZeroDivisionError:
logger.exception("Zero Division Error Caught.")
這樣的紀錄檔會包含足夠的資訊幫助我們找到和修復問題。
紀錄檔可能被攻擊者用來尋找系統的漏洞,因此我們絕對不能在紀錄檔中記錄敏感資訊,如密碼、金鑰和使用者的私有資料。
在這篇文章中,我們詳細介紹了Python的logging模組,包括它的基本介紹,詳解,實踐中的應用,以及一些最佳實踐。總結上述內容:
Python的logging模組是一個非常強大的工具,希望你在閱讀本文後能有更深的理解和更靈活的運用。
如有幫助,請多關注
個人微信公眾號:【Python全視角】
TeahLead_KrisChang,10+年的網際網路和人工智慧從業經驗,10年+技術和業務團隊管理經驗,同濟軟體工程本科,復旦工程管理碩士,阿里雲認證雲服務資深架構師,上億營收AI產品業務負責人。