logging
— Python 的日誌記錄工具¶
此模組定義了為應用程式和庫實現靈活的事件日誌記錄系統的函式和類。
由標準庫模組提供日誌記錄 API 的主要好處是,所有 Python 模組都可以參與日誌記錄,因此您的應用程式日誌可以包含您自己的訊息以及來自第三方模組的訊息。
這是一個慣用用法的簡單示例
# myapp.py
import logging
import mylib
logger = logging.getLogger(__name__)
def main():
logging.basicConfig(filename='myapp.log', level=logging.INFO)
logger.info('Started')
mylib.do_something()
logger.info('Finished')
if __name__ == '__main__':
main()
# mylib.py
import logging
logger = logging.getLogger(__name__)
def do_something():
logger.info('Doing something')
如果您執行 *myapp.py*,您應該在 *myapp.log* 中看到以下內容
INFO:__main__:Started
INFO:mylib:Doing something
INFO:__main__:Finished
這種慣用用法的關鍵特性是,大部分程式碼只是使用 getLogger(__name__)
建立模組級記錄器,並使用該記錄器執行任何所需的日誌記錄。這既簡潔,又允許下游程式碼在需要時進行細粒度的控制。傳送到模組級記錄器的日誌訊息會被轉發到更高級別模組中的記錄器的處理程式,一直到最高級別的記錄器(稱為根記錄器);這種方法稱為分層日誌記錄。
要使日誌記錄有用,需要對其進行配置:為每個記錄器設定級別和目標,可能根據命令列引數或應用程式配置更改特定模組的日誌記錄方式。在大多數情況下,像上面的示例一樣,只需要配置根記錄器,因為所有較低級別的模組級記錄器最終都會將其訊息轉發到其處理程式。basicConfig()
提供了一種快速配置根記錄器的方法,該方法可以處理許多用例。
該模組提供了很多功能和靈活性。如果您不熟悉日誌記錄,最好的方法是檢視教程(**請參閱上面的和右側的連結**)。
模組定義的基本類及其屬性和方法在以下各節中列出。
記錄器公開應用程式程式碼直接使用的介面。
處理程式將日誌記錄(由記錄器建立)傳送到適當的目標。
過濾器提供更細粒度的工具,用於確定要輸出哪些日誌記錄。
格式化程式指定最終輸出中日誌記錄的佈局。
Logger 物件¶
記錄器具有以下屬性和方法。請注意,不應直接例項化記錄器,而應始終透過模組級函式 logging.getLogger(name)
例項化。使用相同的名稱多次呼叫 getLogger()
將始終返回對同一 Logger 物件的引用。
name
可能是句點分隔的分層值,例如 foo.bar.baz
(儘管例如,它也可能只是普通的 foo
)。在分層列表中更靠下的記錄器是列表中更高位置的記錄器的子記錄器。例如,給定一個名為 foo
的記錄器,名稱為 foo.bar
、foo.bar.baz
和 foo.bam
的記錄器都是 foo
的後代。此外,所有記錄器都是根記錄器的後代。記錄器名稱層次結構類似於 Python 包層次結構,如果您使用建議的結構 logging.getLogger(__name__)
按模組組織記錄器,則與 Python 包層次結構相同。那是因為在模組中,__name__
是該模組在 Python 包名稱空間中的名稱。
- class logging.Logger¶
- name¶
這是記錄器的名稱,並且是傳遞給
getLogger()
以獲取記錄器的值。注意
此屬性應視為只讀。
- level¶
此記錄器的閾值,由
setLevel()
方法設定。注意
請勿直接設定此屬性 - 始終使用
setLevel()
,它會對傳遞給它的級別進行檢查。
- parent¶
此記錄器的父記錄器。它可能會根據以後例項化的在名稱空間層次結構中更高的記錄器而更改。
注意
此值應視為只讀。
- propagate¶
如果此屬性的計算結果為 true,則除了附加到此記錄器的任何處理程式之外,記錄到此記錄器的事件將傳遞給更高級別(祖先)記錄器的處理程式。訊息直接傳遞到祖先記錄器的處理程式 - 不考慮相關祖先記錄器的級別或過濾器。
如果此屬性的計算結果為 false,則不會將日誌記錄訊息傳遞到祖先記錄器的處理程式。
用一個示例來說明:如果名為
A.B.C
的記錄器的 propagate 屬性的計算結果為 true,則透過方法呼叫(例如logging.getLogger('A.B.C').error(...)
)記錄到A.B.C
的任何事件將 [在透過該記錄器的級別和過濾器設定後] 依次傳遞給附加到名為A.B
、A
和根記錄器的任何處理程式,在首先傳遞給附加到A.B.C
的任何處理程式之後。如果鏈A.B.C
、A.B
、A
中的任何記錄器的propagate
屬性設定為 false,則該記錄器是最後一個向其處理程式提供要處理的事件的記錄器,並且傳播在該點停止。建構函式將此屬性設定為
True
。注意
如果將處理器附加到記錄器和其一個或多個祖先記錄器,則可能會多次發出相同的記錄。一般來說,您不需要將處理器附加到多個記錄器 - 如果您只是將其附加到記錄器層次結構中最高的適當記錄器,那麼它將看到所有後代記錄器記錄的所有事件,前提是它們的 propagate 設定保持為
True
。一個常見的場景是將處理器僅附加到根記錄器,並讓傳播處理其餘的事情。
- handlers¶
直接附加到此記錄器例項的處理器列表。
注意
此屬性應被視為只讀屬性;它通常透過
addHandler()
和removeHandler()
方法進行更改,這些方法使用鎖來確保執行緒安全操作。
- disabled¶
此屬性停用對任何事件的處理。它在初始化程式中設定為
False
,並且僅由日誌配置程式碼更改。注意
此屬性應視為只讀。
- setLevel(level)¶
設定此記錄器的閾值為 level。嚴重性低於 level 的日誌訊息將被忽略;嚴重性等於或高於 level 的日誌訊息將由服務此記錄器的任何處理器發出,除非處理器的級別已設定為高於 level 的嚴重性級別。
建立記錄器時,級別設定為
NOTSET
(這會導致當記錄器是根記錄器時處理所有訊息,或者當記錄器是非根記錄器時委託給父記錄器)。請注意,根記錄器建立時的級別為WARNING
。術語“委託給父級”意味著如果記錄器的級別為 NOTSET,則會遍歷其祖先記錄器的鏈,直到找到級別不是 NOTSET 的祖先,或者到達根為止。
如果找到級別不是 NOTSET 的祖先,則該祖先的級別被視為祖先搜尋開始的記錄器的有效級別,並用於確定如何處理日誌事件。
如果到達根,並且其級別為 NOTSET,則將處理所有訊息。否則,根的級別將用作有效級別。
有關級別列表,請參見 日誌級別。
在 3.2 版本中更改:level 引數現在接受級別的字串表示形式,例如 ‘INFO’,作為整數常量(如
INFO
)的替代方法。但是,請注意,級別在內部儲存為整數,並且諸如getEffectiveLevel()
和isEnabledFor()
之類的方法將返回/期望傳遞整數。
- isEnabledFor(level)¶
指示此記錄器是否會處理嚴重性為 level 的訊息。此方法首先檢查
logging.disable(level)
設定的模組級級別,然後檢查由getEffectiveLevel()
確定的記錄器的有效級別。
- getEffectiveLevel()¶
指示此記錄器的有效級別。如果已使用
setLevel()
設定了NOTSET
以外的值,則會返回該值。否則,層次結構會向根遍歷,直到找到NOTSET
以外的值,並返回該值。返回的值是一個整數,通常是logging.DEBUG
、logging.INFO
等。
- getChild(suffix)¶
返回一個記錄器,該記錄器是此記錄器的後代,由字尾確定。因此,
logging.getLogger('abc').getChild('def.ghi')
將返回與logging.getLogger('abc.def.ghi')
返回的記錄器相同的記錄器。這是一個方便的方法,當父記錄器使用例如__name__
而不是字面字串命名時很有用。在 3.2 版本中新增。
- getChildren()¶
返回一個記錄器集合,這些記錄器是此記錄器的直接子記錄器。因此,例如,
logging.getLogger().getChildren()
可能會返回一個包含名為foo
和bar
的記錄器的集合,但名為foo.bar
的記錄器將不會包含在該集合中。同樣,logging.getLogger('foo').getChildren()
可能會返回一個包含名為foo.bar
的記錄器的集合,但它不會包含一個名為foo.bar.baz
的記錄器。在 3.12 版本中新增。
- debug(msg, *args, **kwargs)¶
在此記錄器上使用級別
DEBUG
記錄訊息。msg 是訊息格式字串,args 是使用字串格式化運算符合併到 msg 中的引數。(請注意,這意味著您可以在格式字串中使用關鍵字,以及一個字典引數。)當沒有提供 args 時,不會對 msg 執行 % 格式化操作。在 kwargs 中檢查四個關鍵字引數:exc_info、stack_info、stacklevel 和 extra。
如果 exc_info 的計算結果不為假,則會導致異常資訊被新增到日誌訊息中。如果提供了異常元組(格式由
sys.exc_info()
返回)或異常例項,則會使用它;否則,將呼叫sys.exc_info()
來獲取異常資訊。第二個可選關鍵字引數是 stack_info,它預設為
False
。如果為 true,則會將堆疊資訊新增到日誌訊息中,包括實際的日誌呼叫。請注意,這與透過指定 exc_info 顯示的堆疊資訊不同:前者是從堆疊底部到當前執行緒中日誌呼叫的堆疊幀,而後者是關於堆疊幀的資訊,這些堆疊幀是在異常發生後在搜尋異常處理程式時展開的。您可以獨立於 exc_info 指定 stack_info,例如,僅顯示您如何在程式碼中達到某個點,即使沒有引發異常。堆疊幀在標題行之後列印,該標題行說
Stack (most recent call last):
這模仿了顯示異常幀時使用的
Traceback (most recent call last):
。第三個可選關鍵字引數是 stacklevel,它預設為
1
。如果大於 1,則在計算為日誌事件建立的LogRecord
中設定的行號和函式名時,將跳過相應數量的堆疊幀。這可以在日誌助手中使用,以便記錄的函式名、檔名和行號不是助手函式/方法的資訊,而是其呼叫者的資訊。此引數的名稱與warnings
模組中的等效引數相呼應。第四個關鍵字引數是 extra,它可用於傳遞一個字典,該字典用於填充為日誌事件建立的
__dict__
LogRecord
,其中包含使用者定義的屬性。 這些自定義屬性可以按需使用。 例如,可以將它們合併到記錄的訊息中。例如FORMAT = '%(asctime)s %(clientip)-15s %(user)-8s %(message)s' logging.basicConfig(format=FORMAT) d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} logger = logging.getLogger('tcpserver') logger.warning('Protocol problem: %s', 'connection reset', extra=d)
會列印如下內容:
2006-02-08 22:20:02,165 192.168.0.1 fbloggs Protocol problem: connection reset
傳遞給 extra 的字典中的鍵不應與日誌系統使用的鍵衝突。(有關日誌系統使用哪些鍵的更多資訊,請參閱 LogRecord 屬性 部分。)
如果您選擇在記錄的訊息中使用這些屬性,則需要小心。例如,在上面的示例中,
Formatter
已設定為格式字串,該格式字串期望LogRecord
的屬性字典中存在 “clientip” 和 “user”。 如果缺少這些屬性,則不會記錄訊息,因為會發生字串格式化異常。因此,在這種情況下,您始終需要傳遞帶有這些鍵的 extra 字典。雖然這可能很煩人,但此功能旨在用於特殊情況,例如在多執行緒伺服器中,相同的程式碼在許多上下文中執行,並且出現的有趣情況取決於此上下文(例如,在上面的示例中,遠端客戶端 IP 地址和經過身份驗證的使用者名稱)。 在這種情況下,很可能會將特殊的
Formatter
與特定的Handler
一起使用。如果沒有處理程式附加到此記錄器(或其任何祖先,考慮到相關的
Logger.propagate
屬性),則訊息將傳送到lastResort
上設定的處理程式。在 3.2 版本中變更: 添加了 stack_info 引數。
在 3.5 版本中變更: exc_info 引數現在可以接受異常例項。
在 3.8 版本中變更: 添加了 stacklevel 引數。
- warning(msg, *args, **kwargs)¶
在此記錄器上記錄級別為
WARNING
的訊息。 引數的解釋與debug()
相同。注意
有一個已過時的方法
warn
,其功能與warning
完全相同。 由於warn
已棄用,請不要使用它,而應使用warning
。
- exception(msg, *args, **kwargs)¶
在此記錄器上記錄級別為
ERROR
的訊息。 引數的解釋與debug()
相同。 異常資訊會新增到日誌訊息中。 此方法應僅從異常處理程式中呼叫。
- addFilter(filter)¶
將指定的過濾器 filter 新增到此記錄器。
- removeFilter(filter)¶
從此記錄器中刪除指定的過濾器 filter。
- filter(record)¶
將此記錄器的過濾器應用於記錄,如果記錄要被處理,則返回
True
。 依次諮詢過濾器,直到其中一個過濾器返回假值。 如果它們都沒有返回假值,則將處理記錄(傳遞給處理程式)。 如果其中一個返回假值,則不會進一步處理記錄。
- addHandler(hdlr)¶
將指定的處理程式 hdlr 新增到此記錄器。
- removeHandler(hdlr)¶
從此記錄器中刪除指定的處理程式 hdlr。
- findCaller(stack_info=False, stacklevel=1)¶
查詢呼叫者的原始檔名和行號。返回檔名、行號、函式名和堆疊資訊作為 4 個元素的元組。堆疊資訊以
None
形式返回,除非 stack_info 為True
。stacklevel 引數是從呼叫
debug()
和其他 API 的程式碼傳遞的。如果大於 1,則在確定要返回的值之前,多餘的值用於跳過堆疊幀。當從輔助/包裝器程式碼呼叫日誌 API 時,這通常很有用,以便事件日誌中的資訊不是指輔助/包裝器程式碼,而是指呼叫它的程式碼。
- handle(record)¶
透過將其傳遞給與此記錄器及其祖先關聯的所有處理程式(直到找到 propagate 的假值)來處理記錄。此方法用於從套接字接收的未醃製記錄,以及本地建立的記錄。使用
filter()
應用記錄器級過濾。
- makeRecord(name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None)¶
這是一個工廠方法,可以在子類中重寫,以建立專門的
LogRecord
例項。
- hasHandlers()¶
檢查此記錄器是否配置了任何處理程式。這是透過查詢此記錄器及其在記錄器層次結構中的父級中的處理程式來完成的。如果找到處理程式,則返回
True
,否則返回False
。當找到一個將“propagate”屬性設定為 false 的記錄器時,該方法將停止向上搜尋層次結構 - 這將是最後一個檢查是否存在處理程式的記錄器。在 3.2 版本中新增。
3.7 版本更改: 記錄器現在可以進行 pickle 和 unpickle 操作。
日誌級別¶
日誌級別的數值在下表中給出。如果您想定義自己的級別,並且需要它們相對於預定義級別具有特定的值,那麼這些級別主要會引起您的興趣。如果您定義一個具有相同數值的級別,它會覆蓋預定義的值;預定義的名稱將丟失。
級別 |
數值 |
含義/何時使用 |
---|---|---|
|
0 |
當在記錄器上設定時,表示將參考祖先記錄器來確定有效級別。如果仍然解析為 |
|
10 |
詳細資訊,通常僅對嘗試診斷問題的開發人員感興趣。 |
|
20 |
確認一切都按預期工作。 |
|
30 |
表明發生了意外情況,或者在不久的將來可能發生問題(例如“磁碟空間不足”)。該軟體仍在按預期工作。 |
|
40 |
由於更嚴重的問題,該軟體無法執行某些功能。 |
|
50 |
一個嚴重的錯誤,表明程式本身可能無法繼續執行。 |
處理程式物件¶
處理程式具有以下屬性和方法。請注意,Handler
永遠不會直接例項化;此類充當更有用的子類的基礎。但是,子類中的 __init__()
方法需要呼叫 Handler.__init__()
。
- class logging.Handler¶
- __init__(level=NOTSET)¶
透過設定其級別、將過濾器列表設定為空列表並建立一個鎖(使用
createLock()
)來初始化Handler
例項,以序列化對 I/O 機制的訪問。
- createLock()¶
初始化一個執行緒鎖,該執行緒鎖可用於序列化對可能不是執行緒安全的底層 I/O 功能的訪問。
- acquire()¶
獲取使用
createLock()
建立的執行緒鎖。
- setLevel(level)¶
將此處理程式的閾值設定為 level。將忽略嚴重性低於 level 的日誌訊息。建立處理程式時,級別設定為
NOTSET
(這將導致處理所有訊息)。有關級別列表,請參見 日誌級別。
3.2 版本更改: level 引數現在接受級別的字串表示形式,例如 'INFO',作為整數常量(如
INFO
)的替代方法。
- addFilter(filter)¶
將指定的過濾器 filter 新增到此處理程式。
- removeFilter(filter)¶
從此處理程式中刪除指定的過濾器 filter。
- filter(record)¶
將此處理程式的過濾器應用於記錄,如果記錄將被處理,則返回
True
。將依次諮詢過濾器,直到其中一個返回 false 值。如果沒有一個返回 false 值,則將發出該記錄。如果一個返回 false 值,則處理程式將不發出該記錄。
- flush()¶
確保所有日誌輸出都已重新整理。此版本不執行任何操作,旨在由子類實現。
- close()¶
整理處理程式使用的任何資源。此版本不輸出任何內容,但會從
shutdown()
被呼叫時關閉的處理程式內部列表中刪除該處理程式。子類應確保從重寫的close()
方法中呼叫此方法。
- handle(record)¶
根據可能已新增到處理程式的過濾器有條件地發出指定的日誌記錄。使用 I/O 執行緒鎖的獲取/釋放來包裝記錄的實際發出。
- handleError(record)¶
當在
emit()
呼叫期間遇到異常時,應從處理程式中呼叫此方法。如果模組級屬性raiseExceptions
為False
,則會靜默忽略異常。這對於日誌記錄系統來說是大多數情況下需要的 - 大多數使用者不會關心日誌記錄系統中的錯誤,他們更關心應用程式錯誤。但是,如果您願意,可以將此替換為自定義處理程式。指定的記錄是發生異常時正在處理的記錄。(raiseExceptions
的預設值為True
,因為這在開發過程中更有用)。
- format(record)¶
為記錄進行格式化 - 如果設定了格式化程式,則使用它。否則,使用模組的預設格式化程式。
- emit(record)¶
執行實際記錄指定日誌記錄所需的任何操作。此版本旨在由子類實現,因此會引發
NotImplementedError
。警告
此方法在獲取處理程式級鎖後呼叫,該鎖在此方法返回後釋放。重寫此方法時,請注意在呼叫任何呼叫可能執行鎖定的日誌記錄 API 的其他部分時應小心,因為這可能會導致死鎖。具體來說
日誌配置 API 會獲取模組級鎖,然後在配置這些處理程式時獲取各個處理程式級別的鎖。
許多日誌 API 會鎖定模組級別的鎖。如果從該方法呼叫此類 API,則可能會導致死鎖,因為如果在另一個執行緒上進行配置呼叫,該執行緒將嘗試在處理程式級別的鎖之前獲取模組級別的鎖,而此執行緒嘗試在處理程式級別的鎖之後獲取模組級別的鎖(因為在此方法中,已獲取處理程式級別的鎖)。
有關作為標準包含的處理程式列表,請參閱 logging.handlers
。
格式化器物件¶
- class logging.Formatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)¶
負責將
LogRecord
轉換為供人或外部系統解釋的輸出字串。- 引數:
fmt (str) – 給定樣式中用於整個日誌輸出的格式字串。可能的對映鍵來自
LogRecord
物件的 LogRecord 屬性。如果未指定,則使用'%(message)s'
,它只是記錄的訊息。datefmt (str) – 給定樣式中用於日誌輸出的日期/時間部分的格式字串。如果未指定,則使用
formatTime()
中描述的預設值。style (str) – 可以是
'%'
、'{'
或'$'
中的一個,並確定格式字串如何與其資料合併:使用 printf 樣式字串格式化 (%
)、str.format()
({
) 或string.Template
($
) 之一。這僅適用於 fmt 和 datefmt(例如,'%(message)s'
與'{message}'
),而不適用於傳遞給日誌方法的實際日誌訊息。但是,還有 其他方式 可以對日誌訊息使用{
和$
格式化。validate (bool) – 如果
True
(預設值),則不正確或不匹配的 fmt 和 style 將引發ValueError
;例如,logging.Formatter('%(asctime)s - %(message)s', style='{')
。defaults (dict[str, Any]) – 包含要在自定義欄位中使用的預設值的字典。例如,
logging.Formatter('%(ip)s %(message)s', defaults={"ip": None})
在 3.2 版本中更改: 添加了 style 引數。
在 3.8 版本中更改: 添加了 validate 引數。
在 3.10 版本中更改: 添加了 defaults 引數。
- format(record)¶
記錄的屬性字典用作字串格式化操作的運算元。返回結果字串。在格式化字典之前,會執行幾個準備步驟。記錄的 message 屬性是使用 msg % args 計算的。如果格式化字串包含
'(asctime)'
,則呼叫formatTime()
來格式化事件時間。如果存在異常資訊,則使用formatException()
進行格式化,並將其附加到訊息中。請注意,格式化的異常資訊快取在屬性 exc_text 中。這很有用,因為異常資訊可以被 pickle 序列化並透過網路傳送,但如果你有多個Formatter
子類,它們自定義異常資訊的格式化,你應該小心。在這種情況下,你必須在格式化程式完成格式化後清除快取值(透過將 exc_text 屬性設定為None
),以便下一個處理事件的格式化程式不使用快取值,而是重新計算它。如果堆疊資訊可用,則在使用
formatStack()
必要時轉換後,將其附加到異常資訊之後。
- formatTime(record, datefmt=None)¶
應該由想要使用格式化時間的格式化程式從
format()
中呼叫此方法。可以在格式化程式中重寫此方法以滿足任何特定要求,但基本行為如下:如果指定了 datefmt(一個字串),則將其與time.strftime()
一起使用來格式化記錄的建立時間。否則,使用格式 '%Y-%m-%d %H:%M:%S,uuu',其中 uuu 部分是毫秒值,其他字母與time.strftime()
文件一致。此格式的示例時間為2003-01-23 00:29:50,411
。返回結果字串。此函式使用使用者可配置的函式將建立時間轉換為元組。預設情況下,使用
time.localtime()
;要為特定的格式化程式例項更改此設定,請將converter
屬性設定為與time.localtime()
或time.gmtime()
具有相同簽名的函式。要為所有格式化程式更改它,例如,如果你希望所有日誌時間都以 GMT 顯示,請在Formatter
類中設定converter
屬性。在 3.3 版本中更改: 以前,預設格式在此示例中被硬編碼:
2010-09-06 22:38:15,292
,其中逗號前的部分由 strptime 格式字串 ('%Y-%m-%d %H:%M:%S'
) 處理,而逗號後的部分是毫秒值。由於 strptime 沒有用於毫秒的格式佔位符,因此使用另一個格式字串'%s,%03d'
附加毫秒值 — 並且這兩個格式字串都已硬編碼到此方法中。透過更改,這些字串被定義為類級屬性,可以在需要時在例項級別重寫。屬性的名稱是default_time_format
(用於 strptime 格式字串)和default_msec_format
(用於附加毫秒值)。在 3.9 版本中更改:
default_msec_format
可以為None
。
- formatException(exc_info)¶
將指定的異常資訊(
sys.exc_info()
返回的標準異常元組)格式化為字串。此預設實現僅使用traceback.print_exception()
。返回結果字串。
- formatStack(stack_info)¶
將指定的堆疊資訊(由
traceback.print_stack()
返回的字串,但刪除了最後一個換行符)格式化為字串。此預設實現僅返回輸入值。
- class logging.BufferingFormatter(linefmt=None)¶
一個基礎格式化器類,當您想格式化多個記錄時,適合用作子類。您可以傳遞一個
Formatter
例項,您想用它來格式化每一行(對應於單個記錄)。如果未指定,則使用預設格式化器(僅輸出事件訊息)作為行格式化器。- formatHeader(records)¶
返回一個 records 列表的頭部。基本實現只返回空字串。如果您想要特定的行為,例如顯示記錄計數、標題或分隔線,您將需要覆蓋此方法。
返回一個 records 列表的尾部。基本實現只返回空字串。如果您想要特定的行為,例如顯示記錄計數或分隔線,您將需要覆蓋此方法。
- format(records)¶
返回 records 列表的格式化文字。基本實現如果沒有任何記錄,則返回空字串;否則,它返回頭部、每個使用行格式化器格式化的記錄以及尾部的連線。
過濾器物件¶
Filters
可以被 Handlers
和 Loggers
使用,以實現比級別提供的更復雜的過濾。基本過濾器類只允許記錄器層次結構中低於特定點的事件。例如,使用 'A.B' 初始化的過濾器將允許記錄器 'A.B'、'A.B.C'、'A.B.C.D'、'A.B.D' 等記錄的事件,但不允許 'A.BB'、'B.A.B' 等。如果使用空字串初始化,則所有事件都會被傳遞。
- class logging.Filter(name='')¶
返回
Filter
類的例項。如果指定了 name,它將命名一個記錄器,連同其子記錄器,它們的事件將允許透過過濾器。如果 name 是空字串,則允許所有事件。- filter(record)¶
是否要記錄指定的記錄?返回 false 表示否,返回 true 表示是。過濾器可以就地修改日誌記錄,或者返回一個完全不同的記錄例項,它將在事件的任何未來處理中替換原始日誌記錄。
請注意,附加到處理程式的過濾器會在處理程式發出事件之前進行檢查,而附加到記錄器的過濾器會在每次記錄事件時(使用 debug()
, info()
等)進行檢查,然後才將事件傳送給處理程式。這意味著,除非過濾器也已應用於這些後代記錄器,否則由後代記錄器生成的事件不會被記錄器的過濾器設定過濾。
您實際上不需要子類化 Filter
:您可以傳遞任何具有相同語義的 filter
方法的例項。
在 3.2 版本中更改: 您不需要建立專門的 Filter
類,或使用其他具有 filter
方法的類:您可以將函式(或其他可呼叫物件)用作過濾器。過濾邏輯將檢查過濾器物件是否具有 filter
屬性:如果它有,則假定它是一個 Filter
,並呼叫其 filter()
方法。否則,它被假定為一個可呼叫物件,並使用記錄作為單個引數進行呼叫。返回的值應符合 filter()
返回的值。
在 3.12 版本中更改: 您現在可以從過濾器返回一個 LogRecord
例項來替換日誌記錄,而不是就地修改它。這允許附加到 Handler
的過濾器在發出日誌記錄之前修改它,而不會對其他處理程式產生副作用。
雖然過濾器主要用於根據比級別更復雜的標準過濾記錄,但它們會看到附加到它們的處理程式或記錄器處理的每個記錄:如果您想執行諸如計算特定記錄器或處理程式處理了多少條記錄,或在正在處理的 LogRecord
中新增、更改或刪除屬性等操作,這會很有用。顯然,更改 LogRecord 需要謹慎進行,但它確實允許將上下文資訊注入到日誌中(請參閱 使用過濾器來傳遞上下文資訊)。
LogRecord 物件¶
LogRecord
例項由 Logger
在每次記錄某些內容時自動建立,並且可以透過 makeLogRecord()
手動建立(例如,從透過網路接收的 pickle 事件中建立)。
- class logging.LogRecord(name, level, pathname, lineno, msg, args, exc_info, func=None, sinfo=None)¶
包含與正在記錄的事件相關的所有資訊。
主要資訊在 msg 和 args 中傳遞,它們使用
msg % args
組合以建立記錄的message
屬性。- 引數:
name (str) – 用於記錄此
LogRecord
表示的事件的記錄器的名稱。請注意,LogRecord
中的記錄器名稱將始終具有此值,即使它可能由附加到不同(祖先)記錄器的處理程式發出。level (int) – 日誌事件的 數值級別(例如
DEBUG
為10
,INFO
為20
等)。請注意,這會轉換為 LogRecord 的兩個屬性:levelno
表示數值,levelname
表示相應的級別名稱。pathname (str) – 進行日誌記錄呼叫的原始檔的完整字串路徑。
lineno (int) – 進行日誌記錄呼叫的原始檔中的行號。
msg (Any) – 事件描述訊息,它可以是帶有變數資料佔位符的 %-格式字串,或者是一個任意物件(請參閱 使用任意物件作為訊息)。
exc_info (tuple[type[BaseException], BaseException, types.TracebackType] | None) – 一個包含當前異常資訊的元組,由
sys.exc_info()
返回,如果當前沒有異常資訊則為None
。func (str | None) – 發起日誌呼叫的函式或方法的名稱。
sinfo (str | None) – 一個文字字串,表示當前執行緒中從棧底到日誌呼叫處的棧資訊。
- getMessage()¶
返回此
LogRecord
例項的訊息,該訊息是將使用者提供的任何引數與訊息合併後得到的。如果使用者提供給日誌呼叫的訊息引數不是字串,則會呼叫str()
將其轉換為字串。這允許使用使用者定義的類作為訊息,其__str__
方法可以返回要使用的實際格式字串。
在 3.2 版本中更改: 透過提供用於建立記錄的工廠,
LogRecord
的建立變得更加可配置。可以使用getLogRecordFactory()
和setLogRecordFactory()
設定工廠(請參閱此處的工廠簽名)。此功能可用於在建立時將您自己的值注入到
LogRecord
中。您可以使用以下模式old_factory = logging.getLogRecordFactory() def record_factory(*args, **kwargs): record = old_factory(*args, **kwargs) record.custom_attribute = 0xdecafbad return record logging.setLogRecordFactory(record_factory)
使用此模式,可以連結多個工廠,只要它們不覆蓋彼此的屬性或無意中覆蓋上面列出的標準屬性,就不會有意外情況。
LogRecord 屬性¶
LogRecord 有許多屬性,其中大多數屬性是從建構函式的引數派生的。(請注意,LogRecord 建構函式引數和 LogRecord 屬性之間的名稱並不總是完全對應。)這些屬性可用於將記錄中的資料合併到格式字串中。下表按字母順序列出了屬性名稱、它們的含義以及 % 風格格式字串中對應的佔位符。
如果您使用 {} 格式化 (str.format()
),則可以使用 {attrname}
作為格式字串中的佔位符。如果您使用 $ 格式化 (string.Template
),則使用 ${attrname}
的形式。當然,在這兩種情況下,都要將 attrname
替換為您要使用的實際屬性名稱。
在使用 {} 格式化的情況下,您可以透過將格式標誌放在屬性名稱之後,並用冒號將其隔開來指定格式標誌。例如:佔位符 {msecs:03.0f}
會將毫秒值 4
格式化為 004
。有關可用選項的完整詳細資訊,請參閱 str.format()
文件。
屬性名稱 |
格式 |
描述 |
---|---|---|
args |
您不需要自己格式化此項。 |
合併到 |
asctime |
|
建立 |
created |
|
建立 |
exc_info |
您不需要自己格式化此項。 |
異常元組(類似於 |
filename |
|
|
funcName |
|
包含日誌呼叫的函式的名稱。 |
levelname |
|
訊息的文字日誌級別( |
levelno |
|
|
lineno |
|
發出日誌呼叫的源行號(如果可用)。 |
message |
|
記錄的訊息,計算為 |
module |
|
|
msecs |
|
建立 |
msg |
您不需要自己格式化此項。 |
在原始日誌呼叫中傳遞的格式字串。與 |
name |
|
用於記錄呼叫的記錄器的名稱。 |
pathname |
|
發出日誌呼叫的原始檔的完整路徑名(如果可用)。 |
process |
|
程序 ID(如果可用)。 |
processName |
|
程序名稱(如果可用)。 |
relativeCreated |
|
建立 LogRecord 的時間(以毫秒為單位),相對於載入日誌模組的時間。 |
stack_info |
您不需要自己格式化此項。 |
從當前執行緒的棧底到(包括)導致建立此記錄的日誌呼叫的棧幀的堆疊幀資訊(如果可用)。 |
thread |
|
執行緒 ID(如果可用)。 |
threadName |
|
執行緒名稱(如果可用)。 |
taskName |
|
|
在 3.1 版本中更改: 添加了 processName。
在 3.12 版本中更改: 添加了 taskName。
LoggerAdapter 物件¶
LoggerAdapter
例項用於方便地將上下文資訊傳遞到日誌呼叫中。有關用法示例,請參閱關於向日志輸出新增上下文資訊的部分。
- class logging.LoggerAdapter(logger, extra, merge_extra=False)¶
返回一個
LoggerAdapter
的例項,該例項使用底層的Logger
例項、一個類似字典的物件 (extra) 和一個布林值 (merge_extra) 進行初始化,該布林值指示是否應將各個日誌呼叫的 extra 引數與LoggerAdapter
的 extra 合併。預設行為是忽略各個日誌呼叫的 extra 引數,僅使用LoggerAdapter
例項的 extra。- process(msg, kwargs)¶
修改傳遞給日誌呼叫的訊息和/或關鍵字引數,以便插入上下文資訊。此實現採用作為 extra 傳遞給建構函式的物件,並使用鍵 ‘extra’ 將其新增到 kwargs 中。返回值是一個 (msg, kwargs) 元組,其中包含傳入引數的(可能修改過的)版本。
- manager¶
委託給 logger 上的底層
manager
。
- _log¶
委託給 logger 上的底層
_log()
方法。
除了上述內容外,
LoggerAdapter
還支援Logger
的以下方法:debug()
、info()
、warning()
、error()
、exception()
、critical()
、log()
、isEnabledFor()
、getEffectiveLevel()
、setLevel()
和hasHandlers()
。 這些方法具有與Logger
中的對應方法相同的簽名,因此您可以互換使用這兩種型別的例項。在 3.2 版本中更改:
isEnabledFor()
、getEffectiveLevel()
、setLevel()
和hasHandlers()
方法已新增到LoggerAdapter
。這些方法委託給底層記錄器。在 3.6 版本中更改: 添加了屬性
manager
和方法_log()
,它們委託給底層記錄器並允許巢狀介面卡。在 3.13 版本中更改: 添加了 merge_extra 引數。
執行緒安全¶
日誌模組旨線上程安全,無需其客戶端進行任何特殊操作。它透過使用執行緒鎖來實現這一點;有一個鎖用於序列化對模組共享資料的訪問,並且每個處理程式還建立一個鎖用於序列化對其底層 I/O 的訪問。
如果您使用 signal
模組實現非同步訊號處理程式,您可能無法從這些處理程式中使用日誌記錄。這是因為 threading
模組中的鎖實現並非總是可重入的,因此無法從這些訊號處理程式中呼叫。
模組級函式¶
除了上面描述的類之外,還有許多模組級函式。
- logging.getLogger(name=None)¶
返回具有指定名稱的記錄器,如果 name 為
None
,則返回層次結構的根記錄器。如果指定了名稱,則該名稱通常是點分隔的分層名稱,如 'a'、'a.b' 或 'a.b.c.d'。 這些名稱的選擇完全取決於使用日誌記錄的開發人員,但建議使用__name__
,除非您有特定的理由不這樣做,如 記錄器物件 中所述。對具有給定名稱的此函式的所有呼叫都返回相同的記錄器例項。這意味著記錄器例項無需在應用程式的不同部分之間傳遞。
- logging.getLoggerClass()¶
返回標準
Logger
類,或傳遞給setLoggerClass()
的最後一個類。 可以從新的類定義中呼叫此函式,以確保安裝自定義Logger
類不會撤消其他程式碼已應用的自定義項。例如class MyLogger(logging.getLoggerClass()): # ... override behaviour here
- logging.getLogRecordFactory()¶
返回一個可呼叫物件,該物件用於建立
LogRecord
。在 3.2 版本中新增: 已提供此函式以及
setLogRecordFactory()
,以使開發人員可以更好地控制如何構造表示日誌事件的LogRecord
。有關如何呼叫工廠的更多資訊,請參見
setLogRecordFactory()
。
- logging.debug(msg, *args, **kwargs)¶
這是一個方便的函式,它在根記錄器上呼叫
Logger.debug()
。 引數的處理方式與該方法中所述的完全相同。唯一的區別是,如果根記錄器沒有處理程式,則在根記錄器上呼叫
debug
之前,會呼叫basicConfig()
。對於非常短的指令碼或
logging
功能的快速演示,debug
和其他模組級函式可能很方便。但是,大多數程式會希望仔細而明確地控制日誌記錄配置,因此應該首選建立模組級記錄器並在其上呼叫Logger.debug()
(或其他特定級別的方法),如此文件開頭所述。
- logging.warning(msg, *args, **kwargs)¶
在根記錄器上記錄一條級別為
WARNING
的訊息。引數和行為與其他方面與debug()
相同。注意
有一個已過時的函式
warn
,其功能與warning
完全相同。由於warn
已被棄用,請不要使用它,而應使用warning
。
- logging.exception(msg, *args, **kwargs)¶
在根記錄器上記錄一條級別為
ERROR
的訊息。引數和行為與其他方面與debug()
相同。異常資訊將新增到日誌訊息中。此函式應僅從異常處理程式中呼叫。
- logging.disable(level=CRITICAL)¶
為所有記錄器提供一個覆蓋級別 *level*,該級別優先於記錄器自身的級別。當需要暫時降低整個應用程式的日誌輸出時,此函式非常有用。它的作用是停用所有嚴重性為 *level* 及以下的日誌呼叫,因此,如果您使用 INFO 值呼叫它,則所有 INFO 和 DEBUG 事件都將被丟棄,而嚴重性為 WARNING 及以上的事件將根據記錄器的有效級別進行處理。如果呼叫
logging.disable(logging.NOTSET)
,它會有效地刪除此覆蓋級別,以便日誌輸出再次取決於各個記錄器的有效級別。請注意,如果您定義了任何高於
CRITICAL
的自定義日誌級別(不建議這樣做),則您將無法依賴 *level* 引數的預設值,而必須顯式提供合適的值。在 3.7 版本中更改:*level* 引數的預設值更改為級別
CRITICAL
。有關此更改的更多資訊,請參閱 bpo-28524。
- logging.addLevelName(level, levelName)¶
將級別 *level* 與文字 *levelName* 關聯到內部字典中,該字典用於將數字級別對映到文字表示形式,例如,當
Formatter
格式化訊息時。此函式還可用於定義自己的級別。唯一的約束是,所有使用的級別都必須使用此函式註冊,級別應該是正整數,並且它們的嚴重性應按遞增的順序增加。注意
如果您正在考慮定義自己的級別,請參閱關於 自定義級別 的部分。
- logging.getLevelNamesMapping()¶
返回從級別名稱到其相應日誌級別的對映。例如,字串“CRITICAL”對映到
CRITICAL
。返回的對映是從每次呼叫此函式時從內部對映中複製的。在 3.11 版本中新增。
- logging.getLevelName(level)¶
返回日誌級別 *level* 的文字或數字表示形式。
如果 *level* 是預定義級別
CRITICAL
、ERROR
、WARNING
、INFO
或DEBUG
之一,則您將獲得相應的字串。如果您已使用addLevelName()
將級別與名稱關聯,則將返回您與 *level* 關聯的名稱。如果傳入與已定義級別之一對應的數值,則返回相應的字串表示形式。*level* 引數還接受級別的字串表示形式,例如“INFO”。在這種情況下,此函式返回級別的相應數值。
如果未傳入匹配的數值或字串值,則返回字串“Level %s” % level。
注意
級別在內部是整數(因為它們需要在日誌記錄邏輯中進行比較)。此函式用於在整數級別和透過
%(levelname)s
格式說明符(請參閱 LogRecord 屬性)在格式化的日誌輸出中顯示的級別名稱之間進行轉換,反之亦然。在 3.4 版本中更改:在早於 3.4 的 Python 版本中,此函式也可以傳遞文字級別,並且會返回級別的相應數值。這種未記錄的行為被認為是錯誤的,並在 Python 3.4 中刪除,但由於要保持向後相容性,在 3.4.2 中恢復。
- logging.getHandlerByName(name)¶
返回具有指定 *name* 的處理程式,如果不存在具有該名稱的處理程式,則返回
None
。在 3.12 版本中新增。
- logging.getHandlerNames()¶
返回所有已知處理器名稱的不可變集合。
在 3.12 版本中新增。
- logging.makeLogRecord(attrdict)¶
建立並返回一個新的
LogRecord
例項,其屬性由 attrdict 定義。此函式對於獲取透過套接字傳送的 pickledLogRecord
屬性字典,並在接收端將其重新構建為LogRecord
例項非常有用。
- logging.basicConfig(**kwargs)¶
透過建立一個帶有預設
Formatter
的StreamHandler
並將其新增到根記錄器,來為日誌系統進行基本配置。如果根記錄器未定義任何處理器,則函式debug()
、info()
、warning()
、error()
和critical()
將會自動呼叫basicConfig()
。如果根記錄器已經配置了處理器,則此函式不執行任何操作,除非關鍵字引數 force 設定為
True
。注意
此函式應在啟動其他執行緒之前從主執行緒呼叫。在 Python 2.7.1 和 3.2 之前的版本中,如果此函式從多個執行緒呼叫,則可能會(在極少數情況下)將處理器多次新增到根記錄器,從而導致意外的結果,例如日誌中出現重複訊息。
支援以下關鍵字引數。
格式
描述
filename
指定建立一個使用指定檔名而不是
StreamHandler
的FileHandler
。filemode
如果指定了 filename,則以該 模式 開啟檔案。預設為
'a'
。format
對處理器使用指定的格式字串。預設為以冒號分隔的屬性
levelname
、name
和message
。datefmt
使用
time.strftime()
接受的指定日期/時間格式。style
如果指定了 format,則對格式字串使用此樣式。對於 printf-style、
str.format()
或string.Template
,分別為'%'
、'{'
或'$'
之一。預設為'%'
。level
將根記錄器級別設定為指定的級別。
stream
使用指定的流初始化
StreamHandler
。請注意,此引數與 filename 不相容 - 如果兩者都存在,則會引發ValueError
。handlers
如果指定,這應該是一個已建立的處理器可迭代物件,以新增到根記錄器。任何尚未設定格式化程式的處理器都將分配在此函式中建立的預設格式化程式。請注意,此引數與 filename 或 stream 不相容 - 如果兩者都存在,則會引發
ValueError
。force
如果將此關鍵字引數指定為 true,則會刪除並關閉附加到根記錄器的任何現有處理器,然後再執行其他引數指定的配置。
encoding
如果此關鍵字引數與 filename 一起指定,則在建立
FileHandler
時使用其值,因此在開啟輸出檔案時使用。errors
如果此關鍵字引數與 filename 一起指定,則在建立
FileHandler
時使用其值,因此在開啟輸出檔案時使用。如果未指定,則使用值“backslashreplace”。請注意,如果指定了None
,它將按原樣傳遞給open()
,這意味著它的處理方式與傳遞“errors”相同。在 3.2 版本中變更: 添加了 style 引數。
在 3.3 版本中變更: 添加了 handlers 引數。添加了其他檢查,以捕獲指定不相容引數的情況(例如,handlers 與 stream 或 filename 一起,或者 stream 與 filename 一起)。
在 3.8 版本中變更: 添加了 force 引數。
在 3.9 版本中變更: 添加了 encoding 和 errors 引數。
- logging.shutdown()¶
透過重新整理並關閉所有處理器來通知日誌系統執行有序關閉。這應該在應用程式退出時呼叫,並且在此呼叫後不應再使用日誌系統。
匯入日誌模組時,它會將此函式註冊為退出處理器(請參閱
atexit
),因此通常無需手動執行此操作。
- logging.setLoggerClass(klass)¶
告訴日誌系統在例項化記錄器時使用類 klass。該類應定義
__init__()
,以便僅需要一個 name 引數,並且__init__()
應呼叫Logger.__init__()
。此函式通常在需要使用自定義記錄器行為的應用程式例項化任何記錄器之前呼叫。在此呼叫之後,與任何其他時間一樣,請勿使用子類直接例項化記錄器:繼續使用logging.getLogger()
API 獲取記錄器。
- logging.setLogRecordFactory(factory)¶
設定一個用於建立
LogRecord
的可呼叫物件。- 引數:
factory – 用於例項化日誌記錄的工廠可呼叫物件。
在 3.2 版本中新增: 已提供此函式以及
getLogRecordFactory()
,以允許開發人員更好地控制如何構造表示日誌記錄事件的LogRecord
。工廠具有以下簽名
factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, **kwargs)
- name:
記錄器名稱。
- level:
日誌記錄級別(數字)。
- fn:
進行日誌記錄呼叫的檔案的完整路徑名。
- lno:
進行日誌記錄呼叫的檔案中的行號。
- msg:
日誌記錄訊息。
- args:
日誌記錄訊息的引數。
- exc_info:
異常元組或
None
。- func:
呼叫日誌記錄呼叫的函式或方法的名稱。
- sinfo:
堆疊回溯,例如由
traceback.print_stack()
提供,顯示呼叫層次結構。- kwargs:
其他關鍵字引數。
模組級屬性¶
- logging.lastResort¶
透過此屬性可以使用“最後的處理程式”。這是一個寫入
sys.stderr
的StreamHandler
,級別為WARNING
,用於在沒有任何日誌配置的情況下處理日誌事件。最終結果是將訊息列印到sys.stderr
。這取代了之前表示“找不到記錄器 XYZ 的處理程式”的錯誤訊息。如果出於某種原因需要之前的行為,可以將lastResort
設定為None
。在 3.2 版本中新增。
- logging.raiseExceptions¶
用於檢視在處理期間是否應傳播異常。
預設值:
True
。如果
raiseExceptions
為False
,則異常將被靜默忽略。這對於日誌記錄系統來說大多是需要的——大多數使用者不會關心日誌記錄系統中的錯誤,他們更關心應用程式錯誤。
與 warnings 模組整合¶
captureWarnings()
函式可用於將 logging
與 warnings
模組整合。
- logging.captureWarnings(capture)¶
此函式用於開啟和關閉日誌記錄捕獲警告的功能。
如果 capture 為
True
,則warnings
模組發出的警告將重定向到日誌記錄系統。具體來說,將使用warnings.formatwarning()
格式化警告,並將生成的字串記錄到名為'py.warnings'
的記錄器中,嚴重級別為WARNING
。如果 capture 為
False
,則將停止將警告重定向到日誌記錄系統,並且警告將重定向到其原始目標(即在呼叫captureWarnings(True)
之前生效的目標)。
另請參閱
- 模組
logging.config
日誌模組的配置 API。
- 模組
logging.handlers
日誌模組中包含的有用處理程式。
- PEP 282 - 日誌系統
該提案描述了將此功能包含在 Python 標準庫中。
- 原始 Python 日誌包
這是
logging
包的原始來源。此站點提供的軟體包版本適用於 Python 1.5.2、2.1.x 和 2.2.x,這些版本在標準庫中不包含logging
包。