logging - Logging facility for Python - Python 的日志記錄工具
This module defines functions and classes which implement a flexible event logging system for applications and libraries.
這個(gè)模塊為應(yīng)用與庫(kù)定義了實(shí)現(xiàn)靈活的事件日志系統(tǒng)的函數(shù)與類。
The key benefit of having the logging API provided by a standard library module is that all Python modules can participate in logging, so your application log can include your own messages integrated with messages from third-party modules.
使用標(biāo)準(zhǔn)庫(kù)提供的 logging API 最主要的好處是,所有的 Python 模塊都可能參與日志輸出,包括你的日志消息和第三方模塊的日志消息。
The module provides a lot of functionality and flexibility. If you are unfamiliar with logging, the best way to get to grips with it is to see the tutorials (see the links on the right).
這個(gè)模塊提供許多強(qiáng)大而靈活的功能。如果你對(duì) logging 不太熟悉的話,掌握它最好的方式就是查看它對(duì)應(yīng)的教程。
The basic classes defined by the module, together with their functions, are listed below.
該模塊定義的基礎(chǔ)類和函數(shù)都列在下面。
Loggers expose the interface that application code directly uses.
記錄器暴露了應(yīng)用程序代碼直接使用的接口。
Handlers send the log records (created by loggers) to the appropriate destination.
處理程序?qū)⑷罩居涗?(由記錄器創(chuàng)建) 發(fā)送到適當(dāng)?shù)哪繕?biāo)。
Filters provide a finer grained facility for determining which log records to output.
過濾器提供了更精細(xì)的設(shè)施,用于確定要輸出的日志記錄。
Formatters specify the layout of log records in the final output.
格式化程序指定最終輸出中日志記錄的樣式。
facility [f?'s?l?ti]:n. 設(shè)施,設(shè)備,容易,靈巧,才能,天賦
grip [gr?p]:n. 緊握,柄,支配,握拍方式,拍柄繃帶 vt. 緊握,夾緊 vi. 抓住
1. 日志基礎(chǔ)教程
日志是對(duì)軟件執(zhí)行時(shí)所發(fā)生事件的一種追蹤方式。軟件開發(fā)人員對(duì)他們的代碼添加日志調(diào)用,借此來(lái)指示某事件的發(fā)生。一個(gè)事件通過一些包含變量數(shù)據(jù)的描述信息來(lái)描述 (每個(gè)事件發(fā)生時(shí)的數(shù)據(jù)都是不同的)。開發(fā)者還會(huì)區(qū)分事件的重要性,重要性也被稱為等級(jí)或嚴(yán)重性。
1.1 使用日志
對(duì)于簡(jiǎn)單的日志使用來(lái)說(shuō)日志功能提供了一系列便利的函數(shù)。它們是 debug()、info()、warning()、error() 和 critical()。想要決定何時(shí)使用日志,請(qǐng)看下表,其中顯示了對(duì)于每個(gè)通用任務(wù)集合來(lái)說(shuō)最好的工具。
執(zhí)行的任務(wù) | 工具 |
---|---|
對(duì)于命令行或程序的應(yīng)用,結(jié)果顯示在控制臺(tái)。 | print() |
在對(duì)程序的普通操作發(fā)生時(shí)提交事件報(bào)告 (狀態(tài)監(jiān)控和錯(cuò)誤調(diào)查)。 | logging.info() 函數(shù) (當(dāng)有診斷目的需要詳細(xì)輸出信息時(shí)使用 logging.debug() 函數(shù))。 |
提出一個(gè)警告信息基于一個(gè)特殊的運(yùn)行時(shí)事件。 | warnings.warn() 位于代碼庫(kù)中,該事件是可以避免的,需要修改客戶端應(yīng)用以消除告警。logging.warning() 不需要修改客戶端應(yīng)用,但是該事件還是需要引起關(guān)注。 |
對(duì)一個(gè)特殊的運(yùn)行時(shí)事件報(bào)告錯(cuò)誤。 | 引發(fā)異常。 |
報(bào)告錯(cuò)誤而不引發(fā)異常 (如在長(zhǎng)時(shí)間運(yùn)行中的服務(wù)端進(jìn)程的錯(cuò)誤處理)。 | logging.error()、logging.exception() 或 logging.critical() 分別適用于特定的錯(cuò)誤及應(yīng)用領(lǐng)域。 |
日志功能應(yīng)以所追蹤事件級(jí)別或嚴(yán)重性而定。各級(jí)別適用性如下 (以嚴(yán)重性遞增):
級(jí)別 | 何時(shí)使用 |
---|---|
DEBUG | 細(xì)節(jié)信息,僅當(dāng)診斷問題時(shí)適用。 |
INFO | 確認(rèn)程序按預(yù)期運(yùn)行。 |
WARNING | 表明有已經(jīng)或即將發(fā)生的意外 (磁盤空間不足)。程序仍按預(yù)期進(jìn)行。 |
ERROR | 由于嚴(yán)重的問題,程序的某些功能已經(jīng)不能正常執(zhí)行。 |
CRITICAL | 嚴(yán)重的錯(cuò)誤,表明程序已不能繼續(xù)執(zhí)行。 |
默認(rèn)的級(jí)別是
WARNING
,意味著只會(huì)追蹤該級(jí)別及以上的事件,除非更改日志配置。
所追蹤事件可以以不同形式處理。最簡(jiǎn)單的方式是輸出到控制臺(tái)。另一種常用的方式是寫入磁盤文件。
1.2 簡(jiǎn)單的例子
import logging
logging.warning('Watch out!') # will print a message to the console.
logging.info('I told you so') # will not print anything.
如果你在命令行中輸入這些代碼并運(yùn)行,你將會(huì)看到:
WARNING:root:Watch out!
輸出到命令行。INFO 消息并沒有出現(xiàn),因?yàn)槟J(rèn)級(jí)別是 WARNING。打印的信息包含事件的級(jí)別以及在日志調(diào)用中的對(duì)于事件的描述,例如“Watch out!”。暫時(shí)不用擔(dān)心“root”部分:之后會(huì)作出解釋。輸出格式可按需要進(jìn)行調(diào)整,格式化選項(xiàng)同樣會(huì)在之后作出解釋。
1.3 記錄日志到文件
一種非常常見的情況是將日志事件記錄到文件。請(qǐng)確認(rèn)啟動(dòng)新的 Python 解釋器,不要在上一個(gè)環(huán)境中繼續(xù)操作:
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')
現(xiàn)在,如果我們打開日志文件,我們應(yīng)當(dāng)能看到日志信息:
DEBUG:root:This message should go to the log file
INFO:root:So should this
WARNING:root:And this, too
該示例同樣展示了如何設(shè)置日志追蹤級(jí)別的閾值。該示例中,由于我們?cè)O(shè)置的閾值是 DEBUG,所有信息全部打印。
如果你想從命令行設(shè)置日志級(jí)別,例如:
--log=INFO
并且在一些 loglevel 變量中你可以獲得
--log
命令的參數(shù),你可以使用:
getattr(logging, loglevel.upper())
通過 level 參數(shù)獲得你將傳遞給 basicConfig() 的值。你需要對(duì)用戶輸入數(shù)據(jù)進(jìn)行錯(cuò)誤排查,可如下例:
# assuming loglevel is bound to the string value obtained from the
# command line argument. Convert to upper case to allow the user to
# specify --log=DEBUG or --log=debug
numeric_level = getattr(logging, loglevel.upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % loglevel)
logging.basicConfig(level=numeric_level, ...)
對(duì) basicConfig() 的調(diào)用應(yīng)該在 debug()、info() 等的前面。因?yàn)樗辉O(shè)計(jì)為一次性的配置,只有第一次調(diào)用會(huì)進(jìn)行操作,隨后的調(diào)用不會(huì)產(chǎn)生有效操作。
如果多次運(yùn)行上述腳本,則連續(xù)運(yùn)行的消息將追加到文件 example.log。如果你希望每次運(yùn)行重新開始,而不是記住先前運(yùn)行的消息,則可以通過將上例中的調(diào)用更改為來(lái)指定 filemode 參數(shù):
logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG)
輸出將與之前相同,但不再追加進(jìn)日志文件,因此早期運(yùn)行的消息將丟失。
1.4 從多個(gè)模塊記錄日志
如果你的程序包含多個(gè)模塊,這里有一個(gè)如何組織日志記錄的示例:
# 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')
如果你運(yùn)行 myapp.py ,你應(yīng)該在 myapp.log 中看到:
INFO:root:Started
INFO:root:Doing something
INFO:root:Finished
這是你期待看到的。你可以使用 mylib.py 中的模式將此概括為多個(gè)模塊。對(duì)于這種簡(jiǎn)單的使用模式,除了查看事件描述之外,你不能通過查看日志文件來(lái)了解應(yīng)用程序中消息的來(lái)源。
1.5 更改顯示消息的格式
要更改用于顯示消息的格式,你需要指定要使用的格式:
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
請(qǐng)注意,前面示例中出現(xiàn)的 root 已消失。為了簡(jiǎn)單使用,你只需要 levelname (嚴(yán)重性),message (事件描述,包括可變數(shù)據(jù)),也許在事件發(fā)生時(shí)顯示。
1.6 在消息中顯示日期/時(shí)間
要顯示事件的日期和時(shí)間,你可以在格式字符串中放置 ‘%(asctime)s’
import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')
應(yīng)該打印這樣的東西:
2010-12-12 11:41:42,612 is when this event was logged.
日期/時(shí)間顯示的默認(rèn)格式 (如上所示) 類似于 ISO8601 或 RFC 3339。如果你需要更多地控制日期/時(shí)間的格式,請(qǐng)為 basicConfig 提供 datefmt 參數(shù),如下例所示:
import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')
這會(huì)顯示如下內(nèi)容:
12/12/2010 11:46:36 AM is when this event was logged.
datefmt 參數(shù)的格式與 time.strftime() 支持的格式相同。
1.7 記錄變量數(shù)據(jù)
要記錄變量數(shù)據(jù),請(qǐng)使用格式字符串作為事件描述消息,并將變量數(shù)據(jù)作為參數(shù)附加。
import logging
logging.warning('%s before you %s', 'Look', 'leap!')
將顯示:
WARNING:root:Look before you leap!
將可變數(shù)據(jù)合并到事件描述消息中使用舊的 %-s 形式的字符串格式化。這是為了向后兼容:logging 包的出現(xiàn)時(shí)間早于較新的格式化選項(xiàng)例如 str.format() 和 string.Template。 這些較新格式化選項(xiàng)是受支持的。
2. Logging Levels - 日志級(jí)別
The numeric values of logging levels are given in the following table. These are primarily of interest if you want to define your own levels, and need them to have specific values relative to the predefined levels. If you define a level with the same numeric value, it overwrites the predefined value; the predefined name is lost.
日志記錄級(jí)別的數(shù)值在下表中給出。如果你想要定義自己的級(jí)別,并且需要它們具有相對(duì)于預(yù)定義級(jí)別的特定值,那么這些內(nèi)容可能是你感興趣的。如果你定義具有相同數(shù)值的級(jí)別,它將覆蓋預(yù)定義的值,預(yù)定義的名稱丟失。
級(jí)別 - Level | 數(shù)值 - Numeric value |
---|---|
CRITICAL | 50 |
ERROR | 40 |
WARNING | 30 |
INFO | 20 |
DEBUG | 10 |
NOTSET | 0 |
我們自定義日志級(jí)別時(shí)注意不要和默認(rèn)的日志級(jí)別數(shù)值相同,logging 執(zhí)行時(shí)輸出大于等于設(shè)置的日志級(jí)別的日志信息。設(shè)置日志級(jí)別是 INFO,則 INFO、WARNING、ERROR、CRITICAL 級(jí)別的日志都會(huì)輸出。
如果你想要定義自己的級(jí)別,并且需要它們具有相對(duì)于預(yù)定義級(jí)別的特定值,那么這些內(nèi)容可能是你感興趣的。如果你定義具有相同數(shù)值的級(jí)別,它將覆蓋預(yù)定義的值,預(yù)定義的名稱丟失。
級(jí)別也可以與記錄器相關(guān)聯(lián),由開發(fā)人員設(shè)置或通過加載已保存的日志記錄配置。在記錄器上調(diào)用日志記錄方法時(shí),記錄器會(huì)將其自己的級(jí)別與方法調(diào)用關(guān)聯(lián)的級(jí)別進(jìn)行比較。如果記錄器的級(jí)別高于方法調(diào)用的級(jí)別,則實(shí)際上不會(huì)生成任何記錄消息。這是控制日志記錄輸出詳細(xì)程度的基本機(jī)制。
記錄消息被編碼為 LogRecord 類的實(shí)例。當(dāng)記錄器決定實(shí)際記錄事件時(shí),從記錄消息創(chuàng)建 LogRecord 實(shí)例。
記錄消息通過使用 handlers 進(jìn)行調(diào)度機(jī)制,它們是 Handler 類的子類的實(shí)例。處理程序負(fù)責(zé)確保記錄的消息 (以 LogRecord 的形式) 最終位于特定位置 (或一組位置),這對(duì)該消息的目標(biāo)受眾 (例如最終用戶、支持服務(wù)臺(tái)員工、系統(tǒng)管理員、開發(fā)人員)。傳遞處理程序用于特定目標(biāo)的 LogRecord 實(shí)例。每個(gè)記錄器可以有零個(gè)、一個(gè)或多個(gè)與之關(guān)聯(lián)的處理程序 (通過 Logger 的 addHandler() 方法)。除了與記錄器直接關(guān)聯(lián)的任何處理程序之外,還調(diào)用與記錄器的所有祖先相關(guān)聯(lián)的所有處理程序來(lái)分派消息 (除非記錄器的 *propagate 標(biāo)志設(shè)置為 false 值,這將停止傳遞到上級(jí)處理程序)。
就像記錄器一樣,處理程序可以具有與它們相關(guān)聯(lián)的級(jí)別。處理程序的級(jí)別作為過濾器,其方式與記錄器級(jí)別相同。如果處理程序決定調(diào)度一個(gè)事件,則使用 emit() 方法將消息發(fā)送到其目標(biāo)。大多數(shù)用戶定義的 Handler 子類都需要重載 emit() 。
2.1 自定義級(jí)別
定義你自己的級(jí)別是可能的,但不一定是必要的,因?yàn)楝F(xiàn)有級(jí)別是根據(jù)實(shí)踐經(jīng)驗(yàn)選擇的。但是,如果你確信需要自定義級(jí)別,那么在執(zhí)行此操作時(shí)應(yīng)特別小心,如果你正在開發(fā)庫(kù),則定義自定義級(jí)別可能是一個(gè)非常糟糕的主意。這是因?yàn)槿绻鄠€(gè)庫(kù)作者都定義了他們自己的自定義級(jí)別,那么使用開發(fā)人員很難控制和解釋這些多個(gè)庫(kù)的日志記錄輸出,因?yàn)榻o定的數(shù)值可能意味著不同的東西對(duì)于不同的庫(kù)。
3. 進(jìn)階日志教程
日志庫(kù)采用模塊化方法,并提供幾類組件:記錄器、處理程序、過濾器和格式化程序。
- 記錄器暴露了應(yīng)用程序代碼直接使用的接口。
- 處理程序?qū)⑷罩居涗?(由記錄器創(chuàng)建) 發(fā)送到適當(dāng)?shù)哪繕?biāo)。
- 過濾器提供了更精細(xì)的附加功能,用于確定要輸出的日志記錄。
- 格式化程序指定最終輸出中日志記錄的樣式。
日志事件信息在 LogRecord 實(shí)例中的記錄器、處理程序、過濾器和格式化程序之間傳遞。
通過調(diào)用 Logger 類 (以下稱為 loggers,記錄器) 的實(shí)例來(lái)執(zhí)行日志記錄。每個(gè)實(shí)例都有一個(gè)名稱,它們?cè)诟拍钌弦渣c(diǎn) (句點(diǎn)) 作為分隔符排列在命名空間的層次結(jié)構(gòu)中。例如,名為 ‘scan’ 的記錄器是記錄器 scan.text,scan.html 和 scan.pdf 的父級(jí)。記錄器名稱可以是你想要的任何名稱,并指示記錄消息源自的應(yīng)用程序區(qū)域。
在命名記錄器時(shí)使用的一個(gè)好習(xí)慣是在每個(gè)使用日志記錄的模塊中使用模塊級(jí)記錄器,命名如下:
logger = logging.getLogger(__name__)
這意味著記錄器名稱跟蹤包或模塊的層次結(jié)構(gòu),并且直觀地從記錄器名稱顯示記錄事件的位置。
記錄器層次結(jié)構(gòu)的根稱為根記錄器。這是函數(shù) debug()、info()、warning()、error() 和 critical() 使用的記錄器,它們只調(diào)用根記錄器的同名方法。功能和方法具有相同的簽名。根記錄器的名稱在記錄的輸出中打印為 root。
當(dāng)然,可以將消息記錄到不同的地方。軟件包中的支持包含,用于將日志消息寫入文件、HTTP GET/POST 位置、通過 SMTP 發(fā)送電子郵件、通用套接字、隊(duì)列或特定于操作系統(tǒng)的日志記錄機(jī)制 (如 syslog 或 Windows NT 事件日志)。目標(biāo)由 handler 類提供。如果你有任何內(nèi)置處理程序類未滿足的特殊要求,則可以創(chuàng)建自己的日志目標(biāo)類。
默認(rèn)情況下,沒有為任何日志記錄消息設(shè)置目標(biāo)。你可以使用 basicConfig() 指定目標(biāo) (例如控制臺(tái)或文件)。如果你調(diào)用函數(shù) debug()、info()、warning()、error() 和 critical(),他們將檢查是否有設(shè)置目的地;如果沒有設(shè)置,它們將在委托給根記錄器進(jìn)行實(shí)際的消息輸出之前設(shè)置目標(biāo)為控制臺(tái) (sys.stderr) 和默認(rèn)格式的顯示消息。
由 basicConfig() 設(shè)置的消息默認(rèn)格式為:
severity:logger name:message
你可以通過使用 format 參數(shù)將格式字符串傳遞給 basicConfig() 來(lái)更改此設(shè)置。
3.1 記錄流程
記錄器和處理程序中的日志事件信息流程如下圖所示。
3.2 記錄器
Logger 對(duì)象有三重任務(wù)。首先,它們向應(yīng)用程序代碼公開了幾種方法,以便應(yīng)用程序可以在運(yùn)行時(shí)記錄消息。其次,記錄器對(duì)象根據(jù)嚴(yán)重性 (默認(rèn)過濾工具) 或過濾器對(duì)象確定要處理的日志消息。第三,記錄器對(duì)象將相關(guān)的日志消息傳遞給所有感興趣的日志處理程序。
記錄器對(duì)象上使用最廣泛的方法分為兩類:配置和消息發(fā)送。
這些是最常見的配置方法:
- Logger.setLevel() 指定記錄器將處理的最低嚴(yán)重性日志消息,其中 debug 是最低內(nèi)置嚴(yán)重性級(jí)別,critical 是最高內(nèi)置嚴(yán)重性級(jí)別。例如,如果嚴(yán)重性級(jí)別為 INFO,則記錄器將僅處理 INFO、WARNING、ERROR 和 CRITICAL 消息,并將忽略 DEBUG 消息。
- Logger.addHandler() 和 Logger.removeHandler() 從記錄器對(duì)象中添加和刪除處理程序?qū)ο蟆L幚沓绦蛟谝韵聝?nèi)容中有更詳細(xì)的介紹處理程序。
- Logger.addFilter() 和 Logger.removeFilter() 可以添加或移除記錄器對(duì)象中的過濾器。Filter Objects 包含更多的過濾器細(xì)節(jié)。
你不需要始終在你創(chuàng)建的每個(gè)記錄器上調(diào)用這些方法。
配置記錄器對(duì)象后,以下方法將創(chuàng)建日志消息:
-
Logger.debug()、Logger.info()、Logger.warning()、Logger.error() 和 Logger.critical() 都創(chuàng)建日志記錄,包含消息和與其各自方法名稱對(duì)應(yīng)的級(jí)別。該消息實(shí)際上是一個(gè)格式化字符串,它可能包含標(biāo)題字符串替換語(yǔ)法
%s
、%d
、%f
等等。其余參數(shù)是與消息中的替換字段對(duì)應(yīng)的對(duì)象列表。關(guān)于 **kwargs,日志記錄方法只關(guān)注 exc_info 的關(guān)鍵字,并用它來(lái)確定是否記錄異常信息。 - Logger.exception() 創(chuàng)建與 Logger.error() 相似的日志信息。不同之處是,Logger.exception() 同時(shí)還記錄當(dāng)前的堆棧追蹤。僅從異常處理程序調(diào)用此方法。
- Logger.log() 將日志級(jí)別作為顯式參數(shù)。對(duì)于記錄消息而言,這比使用上面列出的日志級(jí)別方便方法更加冗長(zhǎng),但這是自定義日志級(jí)別的方法。
getLogger() 返回對(duì)具有指定名稱的記錄器實(shí)例的引用 (如果已提供),或者如果沒有則返回 root。名稱是以句點(diǎn)分隔的層次結(jié)構(gòu)。多次調(diào)用 getLogger() 具有相同的名稱將返回對(duì)同一記錄器對(duì)象的引用。在分層列表中較低的記錄器是列表中較高的記錄器的子項(xiàng)。例如,給定一個(gè)名為 foo 的記錄器,名稱為 foo.bar 、 foo.bar.baz 和 foo.bam 的記錄器都是 foo 子項(xiàng)。
記錄器具有有效等級(jí)的概念。如果未在記錄器上顯式設(shè)置級(jí)別,則使用其父級(jí)別作為其有效級(jí)別。如果父級(jí)沒有明確的級(jí)別設(shè)置,則檢查其父級(jí)。依此類推,搜索所有上級(jí)元素,直到找到明確設(shè)置的級(jí)別。根記錄器始終具有顯式級(jí)別集 (默認(rèn)情況下為 WARNING )。在決定是否處理事件時(shí),記錄器的有效級(jí)別用于確定事件是否傳遞給記錄器的處理程序。
子記錄器將消息傳播到與其上級(jí)記錄器關(guān)聯(lián)的處理程序。因此,不必為應(yīng)用程序使用的所有記錄器定義和配置處理程序。為頂級(jí)記錄器配置處理程序并根據(jù)需要?jiǎng)?chuàng)建子記錄器就足夠了。(但是,你可以通過將記錄器的 propagate 屬性設(shè)置 False 來(lái)關(guān)閉傳播。)
3.3 處理程序
Handler 對(duì)象負(fù)責(zé)將適當(dāng)?shù)娜罩鞠?(基于日志消息的嚴(yán)重性) 分派給處理程序的指定目標(biāo)。 Logger 對(duì)象可以使用 addHandler() 方法向自己添加零個(gè)或多個(gè)處理程序?qū)ο蟆W鳛槭纠龍?chǎng)景,應(yīng)用程序可能希望將所有日志消息發(fā)送到日志文件,將錯(cuò)誤或更高的所有日志消息發(fā)送到標(biāo)準(zhǔn)輸出,以及將所有關(guān)鍵消息發(fā)送至一個(gè)郵件地址。此方案需要三個(gè)單獨(dú)的處理程序,其中每個(gè)處理程序負(fù)責(zé)將特定嚴(yán)重性的消息發(fā)送到特定位置。
標(biāo)準(zhǔn)庫(kù)包含很多處理程序類型 (參見有用的處理程序 );教程主要使用 StreamHandler 和 FileHandler 。
處理程序中很少有方法可供應(yīng)用程序開發(fā)人員使用。與使用內(nèi)置處理程序?qū)ο?(即不創(chuàng)建自定義處理程序) 的應(yīng)用程序開發(fā)人員相關(guān)的唯一處理程序方法是以下配置方法:
- setLevel() 方法,就像在記錄器對(duì)象中一樣,指定將被分派到適當(dāng)目標(biāo)的最低嚴(yán)重性。為什么有兩個(gè) setLevel() 方法?記錄器中設(shè)置的級(jí)別確定將傳遞給其處理程序的消息的嚴(yán)重性。每個(gè)處理程序中設(shè)置的級(jí)別確定處理程序?qū)l(fā)送哪些消息。
- setFormatter() 選擇一個(gè)該處理程序使用的 Formatter 對(duì)象。
- addFilter() 和 removeFilter() 分別在處理程序上配置和取消配置過濾器對(duì)象。
應(yīng)用程序代碼不應(yīng)直接實(shí)例化并使用 Handler 的實(shí)例。相反, Handler 類是一個(gè)基類,它定義了所有處理程序應(yīng)該具有的接口,并建立了子類可以使用 (或覆蓋) 的一些默認(rèn)行為。
3.4 格式化程序
格式化程序?qū)ο笈渲萌罩鞠⒌淖罱K順序、結(jié)構(gòu)和內(nèi)容。與 logging.Handler 類不同,應(yīng)用程序代碼可以實(shí)例化格式化程序類,但如果應(yīng)用程序需要特殊行為,則可能會(huì)對(duì)格式化程序進(jìn)行子類化。構(gòu)造函數(shù)有三個(gè)可選參數(shù) - 消息格式字符串、日期格式字符串和樣式指示符。
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
如果沒有消息格式字符串,則默認(rèn)使用原始消息。如果沒有日期格式字符串,則默認(rèn)日期格式為:
%Y-%m-%d %H:%M:%S
最后加上毫秒數(shù)。 style 是
%
,
{
或
$
之一。 如果未指定其中一個(gè),則將使用
%
。
如果 style 是
%
,則消息格式字符串使用
%(
樣式字符串替換;可能的鍵值在 LogRecord attributes 中。如果樣式為
{
,則假定消息格式字符串與 str.format() (使用關(guān)鍵字參數(shù))兼容,而如果樣式為
$
,則消息格式字符串應(yīng)符合 string.Template.substitute() 。
以下消息格式字符串將以人類可讀的格式記錄時(shí)間、消息的嚴(yán)重性以及消息的內(nèi)容,按此順序:
'%(asctime)s - %(levelname)s - %(message)s'
格式化程序使用用戶可配置的函數(shù)將記錄的創(chuàng)建時(shí)間轉(zhuǎn)換為元組。默認(rèn)情況下,使用 time.localtime();要為特定格式化程序?qū)嵗拇隧?xiàng),請(qǐng)將實(shí)例的 converter 屬性設(shè)置為具有相同簽名的函數(shù) time.localtime() 或 time.gmtime()。要為所有格式化程序更改它,例如,如果你希望所有記錄時(shí)間都以 GMT 顯示,請(qǐng)?jiān)诟袷交绦蝾愔性O(shè)置 converter 屬性 (對(duì)于 GMT 顯示,設(shè)置為 time.gmtime)。
3.5 配置日志記錄
開發(fā)者可以通過三種方式配置日志記錄:
- 使用調(diào)用上面列出的配置方法的 Python 代碼顯式創(chuàng)建記錄器、處理程序和格式化程序。
- 創(chuàng)建日志配置文件并使用 fileConfig() 函數(shù)讀取它。
- 創(chuàng)建配置信息字典并將其傳遞給 dictConfig() 函數(shù)。
有關(guān)最后兩個(gè)選項(xiàng)的參考文檔,請(qǐng)參閱 Configuration functions。以下示例使用 Python 代碼配置一個(gè)非常簡(jiǎn)單的記錄器/一個(gè)控制臺(tái)處理程序和一個(gè)簡(jiǎn)單的格式化程序:
import logging
# create logger
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
從命令行運(yùn)行此模塊將生成以下輸出:
$ python simple_logging_module.py
2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
2005-03-19 15:10:26,620 - simple_example - INFO - info message
2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
2005-03-19 15:10:26,697 - simple_example - ERROR - error message
2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message
以下 Python 模塊創(chuàng)建的記錄器、處理程序和格式化程序幾乎與上面列出的示例中的相同,唯一的區(qū)別是對(duì)象的名稱:
import logging
import logging.config
logging.config.fileConfig('logging.conf')
# create logger
logger = logging.getLogger('simpleExample')
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
這是 logging.conf 文件:
[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=
輸出幾乎與不基于配置文件的示例相同:
$ python simple_logging_config.py
2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
2005-03-19 15:38:55,979 - simpleExample - INFO - info message
2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message
你可以看到配置文件方法比 Python 代碼方法有一些優(yōu)勢(shì),主要是配置和代碼的分離以及非開發(fā)者輕松修改日志記錄屬性的能力。
fileConfig() 函數(shù)接受一個(gè)默認(rèn)參數(shù) disable_existing_loggers,出于向后兼容的原因,默認(rèn)為 True。這可能是你想要的,也可能不是你想要的,因?yàn)槌窃谂渲弥忻鞔_命名它們 (或一個(gè)上級(jí)節(jié)點(diǎn)中),否則它將導(dǎo)致在 fileConfig() 調(diào)用之前存在的任何非 root 記錄器被禁用。如果需要,請(qǐng)為此參數(shù)指定 False。
傳遞給 dictConfig() 的字典也可以用鍵 disable_existing_loggers 指定一個(gè)布爾值,如果沒有在字典中明確指定,也默認(rèn)被解釋為 True。這會(huì)導(dǎo)致上面描述的記錄器禁用行為,這可能不是你想要的 - 在這種情況下,明確地為鍵提供 False 值。
請(qǐng)注意,配置文件中引用的類名稱需要相對(duì)于日志記錄模塊,或者可以使用常規(guī)導(dǎo)入機(jī)制解析的絕對(duì)值。因此,你可以使用 WatchedFileHandler (相對(duì)于日志記錄模塊) 或 mypackage.mymodule.MyHandler (對(duì)于在 mypackage 包中定義的類和模塊 mymodule,其中 mypackage 在 Python 導(dǎo)入路徑上可用)。
在 Python 3.2 中,引入了一種新的配置日志記錄的方法,使用字典來(lái)保存配置信息。 這提供了上述基于配置文件方法的功能的超集,并且是新應(yīng)用程序和部署的推薦配置方法。因?yàn)?Python 字典用于保存配置信息,并且由于你可以使用不同的方式填充該字典,因此你有更多的配置選項(xiàng)。例如,你可以使用 JSON 格式的配置文件,或者如果你有權(quán)訪問 YAML 處理功能,則可以使用 YAML 格式的文件來(lái)填充配置字典。當(dāng)然,你可以在 Python 代碼中構(gòu)造字典,通過套接字以 pickle 形式接收它,或者使用對(duì)你的應(yīng)用程序合理的任何方法。
以下是與上述相同配置的示例,采用 YAML 格式,用于新的基于字典的方法:
version: 1
formatters:
simple:
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
loggers:
simpleExample:
level: DEBUG
handlers: [console]
propagate: no
root:
level: DEBUG
handlers: [console]
有關(guān)使用字典進(jìn)行日志記錄的更多信息,請(qǐng)參閱 Configuration functions。
如果未提供日志記錄配置,則可能出現(xiàn)需要輸出日志記錄事件但無(wú)法找到輸出事件的處理程序的情況。在這些情況下,日志包的行為取決于 Python 版本。
3.6 配置庫(kù)的日志記錄
在開發(fā)使用日志記錄的庫(kù)時(shí),你應(yīng)該注意記錄庫(kù)如何使用日志記錄 - 例如,使用的記錄器的名稱。還需要考慮其日志記錄配置。如果應(yīng)用程序不使用日志記錄,并且?guī)齑a進(jìn)行日志記錄調(diào)用,那么嚴(yán)重性為“WARNING”及更高級(jí)別的事件將打印到 sys.stderr。這被認(rèn)為是最好的默認(rèn)行為。
如果由于某種原因,你不希望在沒有任何日志記錄配置的情況下打印這些消息,則可以將無(wú)操作處理程序附加到庫(kù)的頂級(jí)記錄器。這樣可以避免打印消息,因?yàn)閷⑹冀K為庫(kù)的事件找到處理程序:它不會(huì)產(chǎn)生任何輸出。如果庫(kù)用戶配置應(yīng)用程序使用的日志記錄,可能是配置將添加一些處理程序,如果級(jí)別已適當(dāng)配置,則在庫(kù)代碼中進(jìn)行的日志記錄調(diào)用將正常地將輸出發(fā)送給這些處理程序。
日志包中包含一個(gè)不做任何事情的處理程序:NullHandler (自 Python 3.1 起)。可以將此處理程序的實(shí)例添加到庫(kù)使用的日志記錄命名空間的頂級(jí)記錄器中 (如果你希望在沒有日志記錄配置的情況下阻止庫(kù)的記錄事件輸出到 sys.stderr)。如果庫(kù) foo 的所有日志記錄都是使用名稱匹配 ‘foo.x’,‘foo.x.y’ 等的記錄器完成的,那么代碼:
import logging
logging.getLogger('foo').addHandler(logging.NullHandler())
應(yīng)該有預(yù)計(jì)的效果。如果一個(gè)組織生成了許多庫(kù),則指定的記錄器名稱可以是 “orgname.foo” 而不僅僅是 “foo” 。
不要將 NullHandler 以外的任何處理程序添加到庫(kù)的記錄器中 。這是因?yàn)樘幚沓绦虻呐渲檬鞘褂媚愕膸?kù)的應(yīng)用程序開發(fā)人員的權(quán)利。應(yīng)用程序開發(fā)人員了解他們的目標(biāo)受眾以及哪些處理程序最適合他們的應(yīng)用程序:如果你在底層添加處理程序,則可能會(huì)干擾他們執(zhí)行單元測(cè)試和提供符合其要求的日志的能力。
4. logging.basicConfig(**kwargs)
Does basic configuration for the logging system by creating a StreamHandler with a default Formatter and adding it to the root logger. The functions debug(), info(), warning(), error() and critical() will call basicConfig() automatically if no handlers are defined for the root logger.
通過使用默認(rèn) Formatter 創(chuàng)建 StreamHandler 并將其添加到根記錄器來(lái)為日志記錄系統(tǒng)執(zhí)行基本配置。如果沒有為根記錄器定義處理程序,函數(shù) debug(),info(),warning(),error() 和 critical() 將自動(dòng)調(diào)用 basicConfig()。
This function does nothing if the root logger already has handlers configured for it.
如果根記錄器已經(jīng)為其配置了處理程序,則此函數(shù)不執(zhí)行任何操作。
This function should be called from the main thread before other threads are started. In versions of Python prior to 2.7.1 and 3.2, if this function is called from multiple threads, it is possible (in rare circumstances) that a handler will be added to the root logger more than once, leading to unexpected results such as messages being duplicated in the log.
在啟動(dòng)其他線程之前,應(yīng)該從主線程調(diào)用此函數(shù)。在 2.7.1 和 3.2 之前的 Python 版本中,如果從多個(gè)線程調(diào)用此函數(shù),則可能 (在極少數(shù)情況下) 將處理程序多次添加到根記錄器,從而導(dǎo)致意外結(jié)果 (如消息) 被復(fù)制在日志中。
The following keyword arguments are supported.
支持以下關(guān)鍵字參數(shù)。
filename: Specifies that a FileHandler be created, using the specified filename, rather than a StreamHandler.
filename:指定使用指定的文件名而不是 StreamHandler 創(chuàng)建 FileHandler。
指定日志文件名。
filemode: If filename is specified, open the file in this mode. Defaults to
a
.
filemode:如果指定了 filename,則以此模式打開文件。默認(rèn)為
a
。
指定日志文件打開模式
w
或
a
。
format: Use the specified format string for the handler.
format:為處理程序使用指定的格式字符串。
%(levelno)s:打印日志級(jí)別的數(shù)值
%(levelname)s:打印日志級(jí)別的名稱
%(pathname)s:打印當(dāng)前執(zhí)行程序的路徑,其實(shí)就是 sys.argv[0]
%(filename)s:打印當(dāng)前執(zhí)行程序名
%(funcName)s:打印日志的當(dāng)前函數(shù)
%(lineno)d:打印日志的當(dāng)前行號(hào)
%(asctime)s:打印日志的時(shí)間
%(thread)d:打印線程 ID
%(threadName)s:打印線程名稱
%(process)d:打印進(jìn)程 ID
%(message)s:打印日志信息
datefmt: Use the specified date/time format, as accepted by time.strftime().
datefmt:使用 time.strftime() 接受的指定日期/時(shí)間格式。
指定時(shí)間格式。
style: If format is specified, use this style for the format string. One of
%
,
{
or
$
for printf-style, str.format() or string.Template respectively. Defaults to
%
.
style:如果指定了 format,請(qǐng)將此樣式用于格式字符串。One of
%
,
{
or
$
for printf-style, str.format() or string.Template respectively. Defaults to
%
.
level: Set the root logger level to the specified level.
level:將根記錄器級(jí)別設(shè)置為指定級(jí)別。
設(shè)置日志級(jí)別,默認(rèn) logging.WARNNING。
stream: Use the specified stream to initialize the StreamHandler. Note that this argument is incompatible with filename - if both are present, a ValueError is raised.
stream:使用指定的流初始化 StreamHandler。請(qǐng)注意,此參數(shù)與 filename 不兼容 - 如果兩者都存在,則引發(fā) ValueError。
指定日志的輸出流,可以指定輸出到 sys.stderr、sys.stdout 或文件,默認(rèn)輸出到 sys.stderr,當(dāng) stream 和 filename 同時(shí)指定時(shí),stream 被忽略。
handlers: If specified, this should be an iterable of already created handlers to add to the root logger. Any handlers which don’t already have a formatter set will be assigned the default formatter created in this function. Note that this argument is incompatible with filename or stream - if both are present, a ValueError is raised.
處理程序:如果指定,則應(yīng)該是已創(chuàng)建的處理程序的可迭代,以添加到根記錄程序。任何沒有格式化程序集的處理程序都將被分配在此函數(shù)中創(chuàng)建的默認(rèn)格式化程序。請(qǐng)注意,此參數(shù)與 filename 或 stream 不兼容 - 如果兩者都存在,則引發(fā) ValueError。
4.1 基本使用方式
默認(rèn)的日志級(jí)別被設(shè)置為 WARNING。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
logging.basicConfig()
logging.debug('This is a debug message.')
logging.info('This is an info message.')
logging.warning('This is a warning message.')
logging.error('This is an error message.')
logging.critical('This is a critical message.')
/usr/bin/python2.7
WARNING:root:This is a warning message.
ERROR:root:This is an error message.
CRITICAL:root:This is a critical message.
Process finished with exit code 0
4.2 基本使用方式
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logging.debug('This is a debug message.')
logging.info('This is an info message.')
logging.warning('This is a warning message.')
logging.error('This is an error message.')
logging.critical('This is a critical message.')
控制臺(tái)輸出日志,
level=logging.INFO
。
/usr/bin/python2.7 /home/strong/git_workspace/MonoGRNet/test.py
2019-06-23 10:34:56,857 - root - INFO - This is an info message.
2019-06-23 10:34:56,857 - root - WARNING - This is a warning message.
2019-06-23 10:34:56,857 - root - ERROR - This is an error message.
2019-06-23 10:34:56,858 - root - CRITICAL - This is a critical message.
Process finished with exit code 0
4.3 基本使用方式
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logging.debug('This is a debug message.')
logging.info('This is an info message.')
logging.warning('This is a warning message.')
logging.error('This is an error message.')
logging.critical('This is a critical message.')
控制臺(tái)輸出日志,
level=logging.DEBUG
。
/usr/bin/python2.7 /home/strong/git_workspace/MonoGRNet/test.py
2019-06-23 10:37:36,742 - root - DEBUG - This is a debug message.
2019-06-23 10:37:36,742 - root - INFO - This is an info message.
2019-06-23 10:37:36,742 - root - WARNING - This is a warning message.
2019-06-23 10:37:36,742 - root - ERROR - This is an error message.
2019-06-23 10:37:36,742 - root - CRITICAL - This is a critical message.
Process finished with exit code 0
5. 有用的處理程序
作為 Handler 基類的補(bǔ)充,提供了很多有用的子類:
StreamHandler 實(shí)例發(fā)送消息到流 (類似文件對(duì)象)。
FileHandler 實(shí)例將消息發(fā)送到硬盤文件。
BaseRotatingHandler 是輪換日志文件的處理程序的基類。它并不應(yīng)該直接實(shí)例化。而應(yīng)該使用 RotatingFileHandler 或 TimedRotatingFileHandler 代替它。
RotatingFileHandler 實(shí)例將消息發(fā)送到硬盤文件,支持最大日志文件大小和日志文件輪換。
TimedRotatingFileHandler 實(shí)例將消息發(fā)送到硬盤文件,以特定的時(shí)間間隔輪換日志文件。
SocketHandler 實(shí)例將消息發(fā)送到 TCP/IP 套接字。從 3.4 開始,也支持 Unix 域套接字。
DatagramHandler 實(shí)例將消息發(fā)送到 UDP 套接字。從 3.4 開始,也支持 Unix 域套接字。
SMTPHandler 實(shí)例將消息發(fā)送到指定的電子郵件地址。
SysLogHandler 實(shí)例將消息發(fā)送到 Unix syslog 守護(hù)程序,可能在遠(yuǎn)程計(jì)算機(jī)上。
NTEventLogHandler 實(shí)例將消息發(fā)送到 Windows NT/2000/XP 事件日志。
MemoryHandler 實(shí)例將消息發(fā)送到內(nèi)存中的緩沖區(qū),只要滿足特定條件,緩沖區(qū)就會(huì)刷新。
HTTPHandler 實(shí)例使用 GET 或 POST 方法將消息發(fā)送到 HTTP 服務(wù)器。
WatchedFileHandler 實(shí)例會(huì)監(jiān)視他們要寫入日志的文件。如果文件發(fā)生更改,則會(huì)關(guān)閉該文件并使用文件名重新打開。此處理程序僅在類 Unix 系統(tǒng)上有用; Windows 不支持依賴的基礎(chǔ)機(jī)制。
QueueHandler 實(shí)例將消息發(fā)送到隊(duì)列,例如在 queue 或 multiprocessing 模塊中實(shí)現(xiàn)的隊(duì)列。
NullHandler 實(shí)例對(duì)錯(cuò)誤消息不執(zhí)行任何操作。它們由想要使用日志記錄的庫(kù)開發(fā)人員使用,但是想要避免如果庫(kù)用戶沒有配置日志記錄,則顯示 “無(wú)法找到記錄器 XXX 的消息處理器” 消息的情況。有關(guān)更多信息,請(qǐng)參閱 配置庫(kù)的日志記錄 。
The NullHandler、StreamHandler 和 FileHandler 類在核心日志包中定義。其他處理程序定義在 logging.handlers 中。(還有另一個(gè)子模塊 logging.config,用于配置功能)
記錄的消息被格式化為通過 Formatter 類的實(shí)例進(jìn)行呈現(xiàn)。 它們使用適合與 % 運(yùn)算符一起使用的格式字符串和字典進(jìn)行初始化。
對(duì)于批量格式化多個(gè)消息,可以使用 BufferingFormatter 的實(shí)例。除了格式字符串(應(yīng)用于批處理中的每個(gè)消息)之外,還提供了標(biāo)題和尾部格式字符串。
當(dāng)基于記錄器級(jí)別和處理程序級(jí)別的過濾不夠時(shí),可以將 Filter 的實(shí)例添加到 Logger 和 Handler 實(shí)例 (通過它們的 addFilter() 方法)。在決定進(jìn)一步處理消息之前,記錄器和處理程序都會(huì)查詢其所有過濾器以獲得許可。如果任何過濾器返回 false 值,則不會(huì)進(jìn)一步處理該消息。
基本 Filter 的功能允許按特定的記錄器名稱進(jìn)行過濾。如果使用此功能,則允許通過過濾器發(fā)送到指定記錄器及其子項(xiàng)的消息,并丟棄所有消息。
6. 記錄日志中引發(fā)的異常
日志包設(shè)計(jì)為忽略記錄日志生產(chǎn)時(shí)發(fā)生的異常。這樣,處理日志記錄事件時(shí)發(fā)生的錯(cuò)誤 (例如日志記錄錯(cuò)誤配置、網(wǎng)絡(luò)或其他類似錯(cuò)誤) 不會(huì)導(dǎo)致使用日志記錄的應(yīng)用程序過早終止。
SystemExit 和 KeyboardInterrupt 異常永遠(yuǎn)不會(huì)被忽略。在 Handler 子類的 emit() 方法中發(fā)生的其他異常被傳遞給它的 handleError() 方法。
Handler 中默認(rèn)實(shí)現(xiàn)的 handleError() 檢查是否設(shè)置了模塊級(jí)變量 raiseExceptions。如果有設(shè)置,則會(huì)將跟蹤打印到 sys.stderr。如果未設(shè)置,則忽略異常。
raiseExceptions 默認(rèn)值是 True。這是因?yàn)樵陂_發(fā)期間,你通常希望收到任何發(fā)生異常的通知。建議你將 raiseExceptions 設(shè)置為 False 以供生產(chǎn)環(huán)境使用。
7. 使用任意對(duì)象作為消息
在前面的部分和示例中,都假設(shè)記錄事件時(shí)傳遞的消息是字符串。但是,這不是唯一的可能性。你可以將任意對(duì)象作為消息傳遞,并且當(dāng)日志記錄系統(tǒng)需要將其轉(zhuǎn)換為字符串表示時(shí),將調(diào)用其
__ str__()
方法。實(shí)際上,如果你愿意,你可以完全避免計(jì)算字符串表示。例如,SocketHandler 通過 pickle 并網(wǎng)絡(luò)發(fā)送來(lái)發(fā)出事件。
8. 優(yōu)化
消息參數(shù)的格式化將被推遲,直到無(wú)法避免。但是,計(jì)算傳遞給日志記錄方法的參數(shù)也可能很消耗資源,如果記錄器只是丟棄你的事件,你可能希望避免這樣做。要決定做什么,可以調(diào)用 isEnabledFor() 方法,該方法接受一個(gè) level 參數(shù),如果記錄器為該級(jí)別的調(diào)用創(chuàng)建了該事件,則返回 true。你可以寫這樣的代碼:
if logger.isEnabledFor(logging.DEBUG):
logger.debug('Message with %s, %s', expensive_func1(),
expensive_func2())
因此,如果記錄器的閾值設(shè)置在 DEBUG 以上,則永遠(yuǎn)不會(huì)調(diào)用 expensive_func1() 和 expensive_func2()。
在某些情況下,isEnabledFor() 本身可能比你想要的更消耗資源 (例如,對(duì)于深度嵌套的記錄器,其中顯式級(jí)別僅在記錄器層次結(jié)構(gòu)中設(shè)置為高)。在這種情況下 (或者如果你想避免在緊密循環(huán)中調(diào)用方法),你可以在本地或?qū)嵗兞恐袑⒄{(diào)用的結(jié)果緩存到 isEnabledFor(),并使用它而不是調(diào)用每次方法。只在日志記錄配置在應(yīng)用程序運(yùn)行時(shí)動(dòng)態(tài)更改 (這不常見) 時(shí)需重新計(jì)算這樣的緩存值。
對(duì)于需要對(duì)收集的日志信息進(jìn)行更精確控制的特定應(yīng)用程序,還可以進(jìn)行其他優(yōu)化。 以下是你可以執(zhí)行的操作列表,以避免在你不需要的日志記錄期間進(jìn)行處理:
有關(guān)調(diào)用來(lái)源的信息 - 如何避免收集它
將 logging._srcfile 設(shè)置為 None 。這避免了調(diào)用 sys._getframe() ,如果 PyPy 支持 Python 3.x ,這可能有助于加速 PyPy (無(wú)法加速使用 sys._getframe() 的代碼)等環(huán)境中的代碼.
線程信息 - 如何避免收集它
將 logging.logThreads 置為 0 。
進(jìn)程信息 - 如何避免收集它
將 logging.logProcesses 置為 0 。
核心日志記錄模塊僅包含基本處理程序。如果你不導(dǎo)入 logging.handlers 和 logging.config,它們將不會(huì)占用任何內(nèi)存。
References
https://docs.python.org/zh-cn/3.7/howto/logging.html
https://docs.python.org/zh-cn/3.7/howto/logging-cookbook.html
https://docs.python.org/3.7/library/logging.html
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
