記錄日誌是追蹤事件的一種手段。通過新增日誌,開發者可以清楚地瞭解發生了哪些事件,包括出現了哪些錯誤。logging 模組提供了一系列便捷的函式,用於簡單的日誌記錄。它們分別是 debug()
, info()
, warning()
, error()
和 critical()
。
簡單示例
下面是一個非常簡單的示例:
import logging
logging.warning('Watch out!') # 列印一條資訊到命令列
logging.info('I told you so') # 不會列印任何東西複製程式碼
如果你執行著幾行程式碼,你會看到命令列中輸出以下內容:
WARNING:root:Watch out!複製程式碼
由於 logging 模組預設的級別為 WARNING
,因此 INFO
級別的日誌不會被列印出來。輸出的日誌包含了級別和事件的描述。root
為預設 logger 的名字,我們可以手動更改它,並且自定義日誌的輸出格式。
記錄日誌到檔案
很多情況下,我們會把日誌記錄到檔案中,接下來我們就來看看具體的操作。請重新開啟一個 python 直譯器,而不要直接使用上述例子所用的直譯器,確保 logging 模組能夠被正確配置。
import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')複製程式碼
如果我們開啟 example.log
檔案,可以看到以下內容:
DEBUG:root:This message should go to the log file
INFO:root:So should this
WARNING:root:And this, too複製程式碼
這個例子告訴你如何設定日誌級別,從而控制要記錄的日誌。由於我們在這個例子中設定的級別是 DEBUG
,因此所有的日誌都會被記錄下來。
多個模組記錄日誌
如果你的程式包含了多個模組,這裡有一個例子向你展示瞭如何組織它們的日誌輸出:
# myapp.py
import logging
import mylib
def main():
logging.basicConfig(filename='myapp.log', level=logging.INFO)
logging.info('Started')
mylib.do_something()
logging.info('Finished')
if __name__ == '__main__':
main()複製程式碼
# mylib.py
import logging
def do_something():
logging.info('Doing something')複製程式碼
如果你執行 myapp.py 檔案,你會在 myapp.log 檔案中看到以下內容:
INFO:root:Started
INFO:root:Doing something
INFO:root:Finished複製程式碼
記錄變數的資料
要記錄變數的資料,可以使用一個格式串來格式化輸出,並將變數作為引數傳遞給日誌記錄函式。
import logging
logging.warning('%s before you %s', 'Look', 'leap!')複製程式碼
輸出內容:
WARNING:root:Look before you leap!複製程式碼
你也可以使用 python 自帶的字串格式化函式:
import logging
logging.warning('{} before you {}'.format('Look', 'leap!'))複製程式碼
自定義日誌格式
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')複製程式碼
輸出如下:
DEBUG:This message should appear on the console
INFO:So should this
WARNING:And this, too複製程式碼
注意到之前的例子中出現的 root
在這裡已經消失了。要了解所有能出現在格式串裡的東西,請參考 LogRecord attributes。但如果只是簡單使用,你只需要 levelname
(級別)、message
(事件描述,包括變數資料)以及事件發生的時間,這點將在下面講解。
記錄日期和時間
要在日誌中顯示日期和時間,你需要在格式串中加入 %(asctime)s
:
import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')複製程式碼
輸出如下:
2010-12-12 11:41:42,612 is when this event was logged.複製程式碼
格式串中的時間格式引數與 time.strftime() 中支援的引數相同。
logging 進階指南
logging 模組採取了模組化的方式並提供了幾個元件的類別:logger、handler、filter、formatter。
- logger 提供了程式碼中直接使用的介面
- handler 用於向目的地傳送日誌記錄
- filter 用於過濾特定的日誌記錄
- formatter 指定了日誌記錄最終的輸出樣式
日誌事件資訊在一個 LogRecord 例項中的 logger、handler、filter 和 formatter 之間傳遞。
一個給 logger 命名的好習慣是使用模組級別的 logger。在每一個需要記錄日誌的模組內使用以下方式來給 logger 命名:
logger = logging.getLogger(__name__)複製程式碼
這種情況下,logger 的名字會追蹤包/模組的層次結構,並且我們可以直觀地看到事件是由哪個模組記錄的。
層次結構中最頂級的 logger 稱為 root logger。當我們呼叫 logging 模組的 debug()
, info()
, warning()
, error()
和 critical()
函式時,會使用 root logger 對應的同名方法。這些函式與 root logger 中的同名方法具有相同的引數簽名。root logger 在輸出時名字為 root
。
當然,我們也可以將資訊記錄到不同的目的地。我們可以將日誌記錄到檔案、HTTP GET/POST 位置、郵件(通過 SMTP)、普通套接字或系統專用的日誌機制,例如 syslog 或 Windows NT 事件日誌。目的地由 handler
類進行處理。如果內建的 handler
類沒有滿足你的要求,你可以建立一個自己的日誌目的地類。
預設情況下,不會給日誌資訊設定目的地。你可以使用 basicConfig() 來指定目的地,正如之前所給的例子一樣。如果你呼叫了 debug()
, info()
, warning()
, error()
和 critical()
函式,它們會檢查是否設定了目的地,如果未設定目的地,則預設使用命令列(sys.stderr)作為目的地,並使用預設的格式來顯示資訊。
basicConfig() 函式預設的格式為:
severity:logger name:message複製程式碼
你可以通過傳遞一個格式串以及格式引數給 basicConfig() 來改變輸出格式。關於格式串構建的所有選項,請參考 Formatter Objects。
參考文章:Logging HOWTO