logging.config
--- 日誌記錄配置¶
本節描述了用於配置 logging 模組的 API。
配置函式¶
以下函式用於配置 logging 模組。它們位於 logging.config
模組中。它們的使用是可選的 — 你可以使用這些函式來配置 logging 模組,也可以透過呼叫主 API(定義於 logging
自身中)並定義在 logging
或 logging.handlers
中宣告的處理程式來配置。
- logging.config.dictConfig(config)¶
從字典中獲取日誌記錄配置。該字典的內容在下面的 配置字典架構 中有詳細描述。
如果在配置過程中遇到錯誤,此函式將引發
ValueError
、TypeError
、AttributeError
或ImportError
並附帶適當的描述性訊息。以下是可能引發錯誤的一些條件(可能不完整):level
不是字串,或者是字串但與實際的日誌記錄級別不對應。propagate
的值不是布林值。一個 id 沒有對應的目標。
在增量呼叫期間發現不存在的處理程式 id。
無效的日誌記錄器名稱。
無法解析為內部或外部物件。
解析由
DictConfigurator
類執行,其建構函式接收用於配置的字典,並有一個configure()
方法。logging.config
模組有一個可呼叫屬性dictConfigClass
,初始設定為DictConfigurator
。你可以用自己合適的實現替換dictConfigClass
的值。dictConfig()
呼叫dictConfigClass
並傳入指定的字典,然後呼叫返回物件上的configure()
方法以使配置生效:def dictConfig(config): dictConfigClass(config).configure()
例如,
DictConfigurator
的子類可以在自己的__init__()
中呼叫DictConfigurator.__init__()
,然後設定自定義字首,這些字首可在隨後的configure()
呼叫中使用。dictConfigClass
將被繫結到這個新的子類,然後可以像在預設的、未自定義的狀態下一樣呼叫dictConfig()
。在 3.2 版本加入。
- logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=None)¶
從一個
configparser
格式的檔案中讀取日誌記錄配置。檔案的格式應如 配置檔案格式 中所述。此函式可以從應用程式中多次呼叫,允許終端使用者從各種預設配置中進行選擇(如果開發人員提供了一種機制來呈現選項並載入所選配置)。如果檔案不存在,它將引發
FileNotFoundError
;如果檔案無效或為空,則引發RuntimeError
。- 引數:
fname -- 檔名、類檔案物件,或
RawConfigParser
的派生例項。如果傳入一個RawConfigParser
派生例項,它將被直接使用。否則,將例項化一個ConfigParser
,並由它從fname
中傳入的物件讀取配置。如果該物件有readline()
方法,則假定它是一個類檔案物件並使用read_file()
讀取;否則,假定它是一個檔名並傳遞給read()
。defaults -- 可以在此引數中指定傳遞給
ConfigParser
的預設值。disable_existing_loggers -- 如果指定為
False
,則在呼叫此函式時已存在的日誌記錄器將保持啟用狀態。預設值為True
,因為這能以向後相容的方式啟用舊行為。此行為是停用任何現有的非根日誌記錄器,除非它們或其祖先在日誌記錄配置中被明確命名。encoding -- 當 *fname* 是檔名時,用於開啟檔案的編碼。
在 3.4 版更改: 現在接受
RawConfigParser
子類的例項作為fname
的值。這有助於使用配置檔案,其中日誌記錄配置只是整個應用程式配置的一部分。
使用從檔案讀取的配置,然後由使用應用程式修改(例如,基於命令列引數或執行時環境的其他方面),然後再傳遞給
fileConfig
。
在 3.10 版更改: 添加了 *encoding* 形參。
在 3.12 版更改: 如果提供的檔案不存在、無效或為空,將丟擲異常。
- logging.config.listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)¶
在指定埠上啟動一個套接字伺服器,並監聽新的配置。如果未指定埠,則使用模組的預設
DEFAULT_LOGGING_CONFIG_PORT
。日誌記錄配置將以適合dictConfig()
或fileConfig()
處理的檔案的形式傳送。返回一個Thread
例項,你可以對其呼叫start()
來啟動伺服器,並在適當時join()
。要停止伺服器,請呼叫stopListening()
。verify
引數如果指定,應該是一個可呼叫物件,用於驗證透過套接字接收的位元組是否有效並應被處理。這可以透過加密和/或簽名透過套接字傳送的內容來實現,這樣verify
可呼叫物件就可以執行簽名驗證和/或解密。verify
可呼叫物件會接收一個引數——透過套接字接收的位元組,並應返回待處理的位元組,或者返回None
表示應丟棄這些位元組。返回的位元組可以與傳入的位元組相同(例如,當只進行驗證時),也可以完全不同(例如,如果執行了解密)。要向套接字傳送配置,請讀入配置檔案,並將其作為位元組序列傳送到套接字,序列前有一個使用
struct.pack('>L', n)
打包的四位元組長度字串。備註
由於部分配置會透過
eval()
傳遞,使用此函式可能會給使用者帶來安全風險。雖然該函式僅在localhost
上繫結套接字,因此不接受來自遠端機器的連線,但在某些情況下,不受信任的程式碼可能會在呼叫listen()
的程序的賬戶下執行。具體來說,如果呼叫listen()
的程序執行在使用者互不信任的多使用者機器上,那麼惡意使用者可以透過連線到受害者的listen()
套接字併發送一個執行攻擊者希望在受害者程序中執行的任何程式碼的配置,從而安排在受害者使用者的程序中執行幾乎任意的程式碼。如果使用預設埠,這尤其容易做到,但即使使用不同的埠也不難。為了避免發生這種情況的風險,請使用listen()
的verify
引數來防止應用未識別的配置。在 3.4 版更改: 添加了
verify
引數。備註
如果你想向監聽器傳送不會停用現有日誌記錄器的配置,你需要為配置使用 JSON 格式,這將使用
dictConfig()
進行配置。此方法允許你在傳送的配置中將disable_existing_loggers
指定為False
。
安全考慮¶
日誌配置功能旨在提供便利,部分透過將配置檔案中的文字轉換為日誌配置中使用的 Python 物件來實現——例如,如 使用者定義的物件 中所述。然而,這些相同的機制(從使用者定義的模組匯入可呼叫物件並使用配置中的引數呼叫它們)可用於呼叫任何你想要的程式碼。因此,你應該*極其謹慎地*對待來自不受信任來源的配置檔案,並在實際載入它們之前,確認載入它們不會發生任何不良後果。
配置字典架構¶
描述日誌記錄配置需要列出要建立的各種物件以及它們之間的連線;例如,你可能建立一個名為‘console’的處理程式,然後指定名為‘startup’的日誌記錄器將其訊息傳送到‘console’處理程式。這些物件不限於 logging
模組提供的物件,因為你可能編寫自己的格式化器或處理程式類。這些類的引數可能還需要包括外部物件,如 sys.stderr
。描述這些物件和連線的語法在下面的 物件連線 中定義。
字典架構詳情¶
傳遞給 dictConfig()
的字典必須包含以下鍵:
*version* - 設定為一個整數值,表示架構版本。目前唯一有效的值是 1,但保留此鍵允許架構在保持向後相容性的同時進行演進。
所有其他鍵都是可選的,但如果存在,它們將按下文所述進行解釋。在下文中所有提到“配置字典”的地方,都會檢查特殊的 '()'
鍵,以確定是否需要自定義例項化。如果需要,將使用下面 使用者定義的物件 中描述的機制建立例項;否則,將根據上下文確定要例項化的內容。
*formatters* - 對應的值將是一個字典,其中每個鍵是一個格式化器 ID,每個值是一個描述如何配置相應
Formatter
例項的字典。配置字典中會搜尋以下與建立
Formatter
物件時傳遞的引數相對應的可選鍵:format
datefmt
風格
validate
(自 >=3.8 版本起)defaults
(自 >=3.12 版本起)
一個可選的
class
鍵表示格式化器類的名稱(以點分隔的模組和類名)。例項化引數與Formatter
相同,因此該鍵最適用於例項化Formatter
的自定義子類。例如,備選類可能會以擴充套件或壓縮的格式顯示異常回溯。如果你的格式化器需要不同或額外的配置鍵,你應該使用 使用者定義的物件。*filters* - 對應的值將是一個字典,其中每個鍵是一個過濾器 ID,每個值是一個描述如何配置相應 Filter 例項的字典。
配置字典中會搜尋鍵
name
(預設為空字串),並用它來構造一個logging.Filter
例項。*handlers* - 對應的值將是一個字典,其中每個鍵是一個處理程式 ID,每個值是一個描述如何配置相應 Handler 例項的字典。
配置字典中會搜尋以下鍵:
class
(強制)。這是處理程式類的完全限定名稱。level
(可選)。處理程式的級別。formatter
(可選)。此處理程式的格式化器 ID。filters
(可選)。此處理程式的過濾器 ID 列表。在 3.11 版更改:
filters
除了 id 之外還可以接受過濾器例項。
所有*其他*鍵都作為關鍵字引數傳遞給處理程式的建構函式。例如,給定以下程式碼片段:
handlers: console: class : logging.StreamHandler formatter: brief level : INFO filters: [allow_foo] stream : ext://sys.stdout file: class : logging.handlers.RotatingFileHandler formatter: precise filename: logconfig.log maxBytes: 1024 backupCount: 3
ID 為
console
的處理程式將被例項化為logging.StreamHandler
,使用sys.stdout
作為底層流。ID 為file
的處理程式將被例項化為logging.handlers.RotatingFileHandler
,關鍵字引數為filename='logconfig.log', maxBytes=1024, backupCount=3
。*loggers* - 對應的值將是一個字典,其中每個鍵是一個日誌記錄器名稱,每個值是一個描述如何配置相應 Logger 例項的字典。
配置字典中會搜尋以下鍵:
level
(可選)。日誌記錄器的級別。propagate
(可選)。日誌記錄器的傳播設定。filters
(可選)。此日誌記錄器的過濾器 ID 列表。在 3.11 版更改:
filters
除了 id 之外還可以接受過濾器例項。handlers
(可選)。此日誌記錄器的處理程式 ID 列表。
指定的日誌記錄器將根據指定的級別、傳播、過濾器和處理程式進行配置。
*root* - 這將是根日誌記錄器的配置。配置的處理方式與任何日誌記錄器相同,只是
propagate
設定不適用。*incremental* - 配置是否應被解釋為對現有配置的增量補充。此值預設為
False
,這意味著指定的配置將替換現有配置,其語義與現有的fileConfig()
API 相同。如果指定的值為
True
,則配置將按照 增量配置 一節中的描述進行處理。*disable_existing_loggers* - 是否停用任何現有的非根日誌記錄器。此設定反映了
fileConfig()
中同名引數的行為。如果預設,此引數預設為True
。如果 *incremental* 為True
,則此值將被忽略。
增量配置¶
為增量配置提供完全的靈活性是困難的。例如,因為過濾器和格式化器等物件是匿名的,一旦配置設定好,就無法在擴充配置時引用這些匿名物件。
此外,一旦配置建立,在執行時任意改變日誌記錄器、處理程式、過濾器、格式化器的物件圖並沒有令人信服的理由;日誌記錄器和處理程式的詳細程度可以透過設定級別(對於日誌記錄器,還可設定傳播標誌)來控制。在多執行緒環境中安全地任意改變物件圖是有問題的;雖然不是不可能,但其帶來的好處並不值得增加實現的複雜性。
因此,當配置字典的 incremental
鍵存在且為 True
時,系統將完全忽略任何 formatters
和 filters
條目,僅處理 handlers
條目中的 level
設定,以及 loggers
和 root
條目中的 level
和 propagate
設定。
在配置字典中使用一個值,可以讓配置作為 pickle 化的字典透過網路傳送給套接字監聽器。因此,可以隨時改變一個長期執行的應用程式的日誌詳細程度,而無需停止和重啟應用程式。
物件連線¶
該架構描述了一組日誌記錄物件——日誌記錄器、處理程式、格式化器、過濾器——它們在一個物件圖中相互連線。因此,該架構需要表示物件之間的連線。例如,假設配置完成後,某個日誌記錄器附加了某個處理程式。在本次討論中,我們可以說日誌記錄器代表了兩者之間連線的源,而處理程式代表了目標。當然,在配置好的物件中,這透過日誌記錄器持有對處理程式的引用來表示。在配置字典中,這是透過給每個目標物件一個唯一標識它的 ID,然後在源物件的配置中使用該 ID 來指示源和具有該 ID 的目標物件之間存在連線來完成的。
因此,舉例來說,考慮以下 YAML 程式碼片段:
formatters:
brief:
# configuration for formatter with id 'brief' goes here
precise:
# configuration for formatter with id 'precise' goes here
handlers:
h1: #This is an id
# configuration of handler with id 'h1' goes here
formatter: brief
h2: #This is another id
# configuration of handler with id 'h2' goes here
formatter: precise
loggers:
foo.bar.baz:
# other configuration for logger 'foo.bar.baz'
handlers: [h1, h2]
(注意:這裡使用 YAML 是因為它比等效的 Python 字典原始碼形式更易讀。)
日誌記錄器的 ID 是程式中用於獲取這些日誌記錄器引用的名稱,例如 foo.bar.baz
。格式化器和過濾器的 ID 可以是任何字串值(如上面的 brief
、precise
),它們是臨時的,僅用於處理配置字典和確定物件之間的連線,在配置呼叫完成後不會被持久化。
上述程式碼段表明,名為 foo.bar.baz
的日誌記錄器應附加兩個處理程式,它們由處理程式 ID h1
和 h2
描述。h1
的格式化器由 ID brief
描述,而 h2
的格式化器由 ID precise
描述。
使用者定義的物件¶
該架構支援使用者自定義的處理程式、過濾器和格式化器物件。(日誌記錄器不需要為不同例項設定不同型別,因此本配置架構不支援使用者自定義的日誌記錄器類。)
待配置的物件由詳細描述其配置的字典來定義。在某些情況下,日誌系統能夠根據上下文推斷出如何例項化一個物件,但當需要例項化一個使用者定義的物件時,系統將不知道如何操作。為了為使用者定義的物件例項化提供完全的靈活性,使用者需要提供一個“工廠”——一個可呼叫物件,它接收一個配置字典並返回例項化的物件。這透過在特殊鍵 '()'
下提供工廠的絕對匯入路徑來表示。這裡有一個具體例子:
formatters:
brief:
format: '%(message)s'
default:
format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
datefmt: '%Y-%m-%d %H:%M:%S'
custom:
(): my.package.customFormatterFactory
bar: baz
spam: 99.9
answer: 42
上述 YAML 程式碼片段定義了三個格式化器。第一個,ID 為 brief
,是一個標準的 logging.Formatter
例項,具有指定的格式字串。第二個,ID 為 default
,具有更長的格式,並明確定義了時間格式,將生成一個用這兩個格式字串初始化的 logging.Formatter
。以 Python 原始碼形式表示,brief
和 default
格式化器的配置子字典分別是:
{
'format' : '%(message)s'
}
與
{
'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
'datefmt' : '%Y-%m-%d %H:%M:%S'
}
由於這些字典不包含特殊鍵 '()'
,例項化是根據上下文推斷的:結果是建立了標準的 logging.Formatter
例項。第三個格式化器,ID 為 custom
,其配置子字典為:
{
'()' : 'my.package.customFormatterFactory',
'bar' : 'baz',
'spam' : 99.9,
'answer' : 42
}
這個字典包含了特殊鍵 '()'
,這意味著需要使用者自定義例項化。在這種情況下,將使用指定的工廠可呼叫物件。如果它是一個實際的可呼叫物件,它將被直接使用——否則,如果你指定一個字串(如示例中所示),實際的可呼叫物件將使用正常的匯入機制定位。該可呼叫物件將以配置子字典中的**其餘**項作為關鍵字引數被呼叫。在上面的示例中,ID 為 custom
的格式化器將被假定為由以下呼叫返回:
my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)
警告
上述示例中,像 bar
、spam
和 answer
這樣的鍵的值不應是配置字典或諸如 cfg://foo
或 ext://bar
之類的引用,因為它們不會被配置機制處理,而是按原樣傳遞給可呼叫物件。
使用 '()'
作為特殊鍵是因為它不是一個有效的關鍵字引數名,因此不會與呼叫中使用的關鍵字引數名衝突。'()'
也作為一個助記符,表示對應的值是一個可呼叫物件。
在 3.11 版更改: handlers
和 loggers
的 filters
成員除了 id 之外還可以接受過濾器例項。
你還可以指定一個特殊的鍵 '.'
,其值為一個屬性名到值的對映。如果找到,指定的屬性將在使用者定義的物件返回之前設定到該物件上。因此,對於以下配置:
{
'()' : 'my.package.customFormatterFactory',
'bar' : 'baz',
'spam' : 99.9,
'answer' : 42,
'.' {
'foo': 'bar',
'baz': 'bozz'
}
}
返回的格式化器將具有設定為 'bar'
的屬性 foo
和設定為 'bozz'
的屬性 baz
。
警告
上述示例中,像 foo
和 baz
這樣的屬性值不應是配置字典或諸如 cfg://foo
或 ext://bar
之類的引用,因為它們不會被配置機制處理,而是按原樣作為屬性值設定。
處理程式配置順序¶
處理程式按其鍵的字母順序進行配置,已配置的處理程式會替換架構中 handlers
字典(的工作副本)中的配置字典。如果你使用類似 cfg://handlers.foo
的構造,那麼最初 handlers['foo']
指向名為 foo
的處理程式的配置字典,之後(一旦該處理程式被配置)它將指向已配置的處理程式例項。因此,cfg://handlers.foo
可以解析為字典或處理程式例項。通常,明智的做法是命名處理程式,使得依賴的處理程式在它們所依賴的任何處理程式*之後*配置;這允許在配置依賴於處理程式 foo
的處理程式時使用類似 cfg://handlers.foo
的語法。如果那個依賴的處理程式名為 bar
,就會出現問題,因為會先嚐試配置 bar
而不是 foo
,而此時 foo
尚未被配置。然而,如果依賴的處理程式名為 foobar
,它將在 foo
之後配置,結果是 cfg://handlers.foo
將解析為已配置的處理程式 foo
,而不是其配置字典。
訪問外部物件¶
有時配置需要引用配置之外的物件,例如 sys.stderr
。如果配置字典是使用 Python 程式碼構建的,這很簡單,但當配置透過文字檔案(例如 JSON、YAML)提供時,問題就出現了。在文字檔案中,沒有標準方法來區分 sys.stderr
和字面字串 'sys.stderr'
。為了方便區分,配置系統會在字串值中查詢某些特殊字首並特殊處理它們。例如,如果在配置中提供字面字串 'ext://sys.stderr'
作為值,那麼 ext://
將被剝離,值的其餘部分將使用正常的匯入機制進行處理。
這種字首的處理方式類似於協議處理:有一個通用機制來查詢匹配正則表示式 ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$
的字首,如果 prefix
被識別,suffix
將以依賴於字首的方式進行處理,處理結果將替換字串值。如果字首未被識別,那麼字串值將保持不變。
訪問內部物件¶
除了外部物件,有時也需要引用配置中的物件。配置系統會對其已知的事物隱式地執行此操作。例如,日誌記錄器或處理程式中 level
的字串值 'DEBUG'
將自動轉換為值 logging.DEBUG
,而 handlers
、filters
和 formatter
條目將接受一個物件 ID 並解析為相應的目標物件。
然而,對於 logging
模組不知道的使用者定義物件,需要一種更通用的機制。例如,考慮 logging.handlers.MemoryHandler
,它接受一個 target
引數,該引數是另一個要委託處理的處理器。由於系統已經知道這個類,那麼在配置中,給定的 target
只需要是相關目標處理器的物件 ID,系統就會從 ID 解析出處理器。然而,如果使用者定義了一個 my.package.MyHandler
,它有一個 alternate
處理器,配置系統將不知道 alternate
指的是一個處理器。為了解決這個問題,一個通用的解析系統允許使用者指定
handlers:
file:
# configuration of file handler goes here
custom:
(): my.package.MyHandler
alternate: cfg://handlers.file
字面字串 'cfg://handlers.file'
將以類似於帶有 ext://
字首的字串的方式進行解析,但它會在配置本身中查詢,而不是在匯入名稱空間中。該機制允許透過點或索引進行訪問,方式類似於 str.format
所提供的。因此,給定以下程式碼片段:
handlers:
email:
class: logging.handlers.SMTPHandler
mailhost: localhost
fromaddr: my_app@domain.tld
toaddrs:
- support_team@domain.tld
- dev_team@domain.tld
subject: Houston, we have a problem.
在配置中,字串 'cfg://handlers'
將解析為鍵為 handlers
的字典,字串 'cfg://handlers.email'
將解析為 handlers
字典中鍵為 email
的字典,依此類推。字串 'cfg://handlers.email.toaddrs[1]'
將解析為 'dev_team@domain.tld'
,字串 'cfg://handlers.email.toaddrs[0]'
將解析為值 'support_team@domain.tld'
。subject
值可以使用 'cfg://handlers.email.subject'
或等效的 'cfg://handlers.email[subject]'
來訪問。後一種形式僅在鍵包含空格或非字母數字字元時才需要使用。請注意,鍵中不允許出現字元 [
和 ]
。如果索引值僅由十進位制數字組成,將嘗試使用相應的整數值進行訪問,如果需要,則回退到字串值。
給定一個字串 cfg://handlers.myhandler.mykey.123
,它將解析為 config_dict['handlers']['myhandler']['mykey']['123']
。如果字串指定為 cfg://handlers.myhandler.mykey[123]
,系統將嘗試從 config_dict['handlers']['myhandler']['mykey'][123]
中檢索值,如果失敗,則回退到 config_dict['handlers']['myhandler']['mykey']['123']
。
匯入解析和自定義匯入器¶
匯入解析預設使用內建的 __import__()
函式進行匯入。你可能希望用自己的匯入機制替換它:如果是這樣,你可以替換 DictConfigurator
或其超類 BaseConfigurator
類的 importer
屬性。但是,你需要小心,因為函式是透過描述符從類中訪問的。如果你使用 Python 可呼叫物件進行匯入,並且希望在類級別而不是例項級別定義它,你需要用 staticmethod()
將其包裝。例如:
from importlib import import_module
from logging.config import BaseConfigurator
BaseConfigurator.importer = staticmethod(import_module)
如果你在一個配置器*例項*上設定匯入可呼叫物件,則無需使用 staticmethod()
進行包裝。
配置 QueueHandler 和 QueueListener¶
如果你想配置一個 QueueHandler
,請注意它通常與 QueueListener
結合使用,你可以將它們一起配置。配置後,QueueListener
例項將作為建立的處理程式的 listener
屬性可用,而該處理程式又可以透過 getHandlerByName()
並傳入你在配置中為 QueueHandler
使用的名稱來獲得。配置這對組合的字典架構如下面的 YAML 片段所示。
handlers:
qhand:
class: logging.handlers.QueueHandler
queue: my.module.queue_factory
listener: my.package.CustomListener
handlers:
- hand_name_1
- hand_name_2
...
queue
和 listener
鍵是可選的。
如果存在 queue
鍵,其對應的值可以是以下之一:
一個實現了
Queue.put_nowait
和Queue.get
公共 API 的物件。例如,這可能是一個queue.Queue
的實際例項或其子類,或者透過multiprocessing.managers.SyncManager.Queue()
獲得的代理。當然,這隻有在你在程式碼中構造或修改配置字典時才可能。
一個解析為可呼叫物件的字串,當不帶引數呼叫時,返回要使用的佇列例項。該可呼叫物件可以是一個
queue.Queue
子類或一個返回合適佇列例項的函式,例如my.module.queue_factory()
。一個帶有
'()'
鍵的字典,該字典按照 使用者定義的物件 中討論的常規方式構造。此構造的結果應該是一個queue.Queue
例項。
如果 queue
鍵不存在,則會建立一個標準的無界 queue.Queue
例項並使用它。
如果存在 listener
鍵,其對應的值可以是以下之一:
一個
logging.handlers.QueueListener
的子類。當然,這隻有在你在程式碼中構造或修改配置字典時才可能。一個解析為類的字串,該類是
QueueListener
的子類,例如'my.package.CustomListener'
。一個帶有
'()'
鍵的字典,該字典按照 使用者定義的物件 中討論的常規方式構造。此構造的結果應該是一個與QueueListener
初始化器具有相同簽名的可呼叫物件。
如果 listener
鍵不存在,則使用 logging.handlers.QueueListener
。
handlers
鍵下的值是配置中其他處理程式的名稱(在上述程式碼片段中未顯示),這些處理程式將被傳遞給佇列監聽器。
任何自定義的佇列處理程式和監聽器類都需要定義與 QueueHandler
和 QueueListener
相同的初始化簽名。
3.12 新版功能.
配置檔案格式¶
fileConfig()
所理解的配置檔案格式基於 configparser
的功能。檔案必須包含名為 [loggers]
、[handlers]
和 [formatters]
的節,它們透過名稱標識檔案中定義的每種型別的實體。對於每個這樣的實體,都有一個單獨的節來標識該實體的配置方式。因此,對於 [loggers]
節中名為 log01
的日誌記錄器,相關的配置詳細資訊儲存在名為 [logger_log01]
的節中。類似地,[handlers]
節中名為 hand01
的處理程式,其配置儲存在名為 [handler_hand01]
的節中,而 [formatters]
節中名為 form01
的格式化器,其配置在名為 [formatter_form01]
的節中指定。根日誌記錄器的配置必須在名為 [logger_root]
的節中指定。
備註
fileConfig()
API 比 dictConfig()
API 更早,並且不提供覆蓋某些日誌記錄方面的功能。例如,你不能使用 fileConfig()
來配置 Filter
物件,這些物件提供了超出簡單整數級別的訊息過濾功能。如果你的日誌記錄配置中需要 Filter
的例項,你需要使用 dictConfig()
。請注意,未來的配置功能增強將新增到 dictConfig()
中,因此在方便時考慮過渡到這個較新的 API 是值得的。
檔案中這些節的示例如下。
[loggers]
keys=root,log02,log03,log04,log05,log06,log07
[handlers]
keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
[formatters]
keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
根日誌記錄器必須指定一個級別和一個處理程式列表。下面是一個根日誌記錄器節的示例。
[logger_root]
level=NOTSET
handlers=hand01
level
條目可以是 DEBUG, INFO, WARNING, ERROR, CRITICAL
或 NOTSET
中的一個。僅對於根日誌記錄器,NOTSET
意味著將記錄所有訊息。級別值在 logging
包的名稱空間上下文中進行 求值。
handlers
條目是一個以逗號分隔的處理程式名稱列表,這些名稱必須出現在 [handlers]
節中。這些名稱必須出現在 [handlers]
節中,並在配置檔案中有相應的節。
對於除根日誌記錄器之外的日誌記錄器,需要一些額外資訊。以下示例對此進行了說明。
[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser
level
和 handlers
條目的解釋與根日誌記錄器相同,但如果非根日誌記錄器的級別指定為 NOTSET
,系統會查詢層次結構中更高級別的日誌記錄器以確定該日誌記錄器的有效級別。propagate
條目設定為 1 表示訊息必須從此日誌記錄器傳播到日誌記錄器層次結構中更高級別的處理程式,設定為 0 表示訊息**不**傳播到層次結構中更高級別的處理程式。qualname
條目是日誌記錄器的分層通道名稱,也就是說,是應用程式用來獲取該日誌記錄器的名稱。
指定處理程式配置的節示例如下。
[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)
class
條目表示處理程式的類(由 logging
包的名稱空間中的 eval()
確定)。level
的解釋與日誌記錄器相同,NOTSET
被視為“記錄所有內容”。
formatter
條目指示此處理程式的格式化器的鍵名。如果為空,則使用預設格式化器 (logging._defaultFormatter
)。如果指定了名稱,它必須出現在 [formatters]
節中,並在配置檔案中有相應的節。
args
條目在 logging
包的名稱空間上下文中進行 求值 後,是處理程式類建構函式的引數列表。請參考相關處理程式的建構函式或下面的示例,瞭解典型條目的構造方式。如果未提供,則預設為 ()
。
可選的 kwargs
條目,在 logging
包的名稱空間中進行 求值 後,是處理程式類建構函式的關鍵字引數字典。如果未提供,則預設為 {}
。
[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form02
args=('python.log', 'w')
[handler_hand03]
class=handlers.SocketHandler
level=INFO
formatter=form03
args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
[handler_hand04]
class=handlers.DatagramHandler
level=WARN
formatter=form04
args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
[handler_hand05]
class=handlers.SysLogHandler
level=ERROR
formatter=form05
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
[handler_hand06]
class=handlers.NTEventLogHandler
level=CRITICAL
formatter=form06
args=('Python Application', '', 'Application')
[handler_hand07]
class=handlers.SMTPHandler
level=WARN
formatter=form07
args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
kwargs={'timeout': 10.0}
[handler_hand08]
class=handlers.MemoryHandler
level=NOTSET
formatter=form08
target=
args=(10, ERROR)
[handler_hand09]
class=handlers.HTTPHandler
level=NOTSET
formatter=form09
args=('localhost:9022', '/log', 'GET')
kwargs={'secure': True}
指定格式化程式配置的節以下面的示例為典型。
[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s %(customfield)s
datefmt=
style=%
validate=True
defaults={'customfield': 'defaultvalue'}
class=logging.Formatter
格式化器配置的引數與字典架構 格式化器節 中的鍵相同。
defaults
條目在 logging
包的名稱空間上下文中進行 求值 後,是一個包含自定義格式化欄位預設值的字典。如果未提供,則預設為 None
。
備註
由於使用瞭如上所述的 eval()
,使用 listen()
透過套接字傳送和接收配置會帶來潛在的安全風險。這些風險僅限於在同一臺機器上執行程式碼且互不信任的多個使用者;更多資訊請參見 listen()
文件。
參見
logging
模組logging 模組的 API 參考。
logging.handlers
模組日誌模組附帶的有用的處理器。