logging.config --- 日志記錄配置?

源代碼: Lib/logging/config.py


這一節(jié)描述了用于配置 logging 模塊的 API。

配置函數(shù)?

下列函數(shù)可配置 logging 模塊。 它們位于 logging.config 模塊中。 它們的使用是可選的 --- 要配置 logging 模塊你可以使用這些函數(shù),也可以通過(guò)調(diào)用主 API (在 logging 本身定義) 并定義在 logginglogging.handlers 中聲明的處理器。

logging.config.dictConfig(config)?

從一個(gè)字典獲取日志記錄配置。 字典的內(nèi)容描述見(jiàn)下文的 配置字典架構(gòu)。

如果在配置期間遇到錯(cuò)誤,此函數(shù)將引發(fā) ValueError, TypeError, AttributeErrorImportError 并附帶適當(dāng)?shù)拿枋鲂韵ⅰ?下面是將會(huì)引發(fā)錯(cuò)誤的(可能不完整的)條件列表:

  • level 不是字符串或者不是對(duì)應(yīng)于實(shí)際日志記錄級(jí)別的字符串。

  • propagate 值不是布爾類型。

  • id 沒(méi)有對(duì)應(yīng)的目標(biāo)。

  • 在增量調(diào)用期間發(fā)現(xiàn)不存在的處理器 id。

  • 無(wú)效的日志記錄器名稱。

  • 無(wú)法解析為內(nèi)部或外部對(duì)象。

解析由 DictConfigurator 類執(zhí)行,該類的構(gòu)造器可傳入用于配置的字典,并且具有 configure() 方法。 logging.config 模塊具有可調(diào)用屬性 dictConfigClass,其初始值設(shè)為 DictConfigurator。 你可以使用你自己的適當(dāng)實(shí)現(xiàn)來(lái)替換 dictConfigClass 的值。

dictConfig() 會(huì)調(diào)用 dictConfigClass 并傳入指定的字典,然后在所返回的對(duì)象上調(diào)用 configure() 方法以使配置生效:

def dictConfig(config):
    dictConfigClass(config).configure()

例如,DictConfigurator 的子類可以在它自己的 __init__() 中調(diào)用 DictConfigurator.__init__(),然后設(shè)置可以在后續(xù) configure() 調(diào)用中使用的自定義前綴。 dictConfigClass 將被綁定到這個(gè)新的子類,然后就可以與在默認(rèn)的未定制狀態(tài)下完全相同的方式調(diào)用 dictConfig()

3.2 新版功能.

logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=None)?

從一個(gè) configparser 格式文件中讀取日志記錄配置。 文件格式應(yīng)當(dāng)與 配置文件格式 中的描述一致。 此函數(shù)可在應(yīng)用程序中被多次調(diào)用,以允許最終用戶在多個(gè)預(yù)設(shè)配置中進(jìn)行選擇(如果開(kāi)發(fā)者提供了展示選項(xiàng)并加載選定配置的機(jī)制)。

參數(shù)
  • fname -- 一個(gè)文件名,或一個(gè)文件類對(duì)象,或是一個(gè)派生自 RawConfigParser 的實(shí)例。 如果傳入了一個(gè)派生自 RawConfigParser 的實(shí)例,它會(huì)被原樣使用。 否則,將會(huì)實(shí)例化一個(gè) Configparser,并且它會(huì)從作為 fname 傳入的對(duì)象中讀取配置。 如果存在 readline() 方法,則它會(huì)被當(dāng)作一個(gè)文件類對(duì)象并使用 read_file() 來(lái)讀?。辉谄渌闆r下,它會(huì)被當(dāng)作一個(gè)文件名并傳遞給 read()。

  • defaults -- 要傳遞給 ConfigParser 的默認(rèn)值可在此參數(shù)中指定。

  • disable_existing_loggers -- 如果指定為 False,則當(dāng)執(zhí)行此調(diào)用時(shí)已存在的日志記錄器會(huì)被保持啟用。 默認(rèn)值為 True 因?yàn)檫@將以向下兼容的方式啟用舊有行為。 此行為是禁用任何已存在的非根日志記錄器除非它們或它們的上級(jí)在日志配置中被顯式地指定。 :param encoding: 當(dāng) fname 為文件名時(shí)用于打開(kāi)文件的編碼格式。

在 3.4 版更改: 現(xiàn)在接受 RawConfigParser 子類的實(shí)例作為 fname 的值。 這有助于:

  • 使用一個(gè)配置文件,其中日志記錄配置只是全部應(yīng)用程序配置的一部分。

  • 使用從一個(gè)文件讀取的配置,它隨后會(huì)在被傳給 fileConfig 之前由使用配置的應(yīng)用程序來(lái)修改(例如基于命令行參數(shù)或運(yùn)行時(shí)環(huán)境的其他部分)。

3.10 新版功能: 增加了 encoding 形參。

logging.config.listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)?

在指定的端口上啟動(dòng)套接字服務(wù)器,并監(jiān)聽(tīng)新的配置。 如果未指定端口,則會(huì)使用模塊默認(rèn)的 DEFAULT_LOGGING_CONFIG_PORT。 日志記錄配置將作為適合由 dictConfig()fileConfig() 進(jìn)行處理的文件來(lái)發(fā)送。 返回一個(gè) Thread 實(shí)例,你可以在該實(shí)例上調(diào)用 start() 來(lái)啟動(dòng)服務(wù)器,對(duì)該服務(wù)器你可以在適當(dāng)?shù)臅r(shí)候執(zhí)行 join()。 要停止該服務(wù)器,請(qǐng)調(diào)用 stopListening()。

如果指定 verify 參數(shù),則它應(yīng)當(dāng)是一個(gè)可調(diào)用對(duì)象,該對(duì)象應(yīng)當(dāng)驗(yàn)證通過(guò)套接字接收的字節(jié)數(shù)據(jù)是否有效且應(yīng)被處理。 這可以通過(guò)對(duì)通過(guò)套接字發(fā)送的內(nèi)容進(jìn)行加密和/或簽名來(lái)完成,這樣 verify 可調(diào)用對(duì)象就能執(zhí)行簽名驗(yàn)證和/或解密。 verify 可調(diào)用對(duì)象的調(diào)用會(huì)附帶一個(gè)參數(shù) —— 通過(guò)套接字接收的字節(jié)數(shù)據(jù) —— 并應(yīng)當(dāng)返回要處理的字節(jié)數(shù)據(jù),或者返回 None 來(lái)指明這些字節(jié)數(shù)據(jù)應(yīng)當(dāng)被丟棄。 返回的字節(jié)數(shù)據(jù)可以與傳入的字節(jié)數(shù)據(jù)相同(例如在只執(zhí)行驗(yàn)證的時(shí)候),或者也可以完全不同(例如在可能執(zhí)行了解密的時(shí)候)。

要將配置發(fā)送到套接字,請(qǐng)讀取配置文件并將其作為字節(jié)序列發(fā)送到套接字,字節(jié)序列要以使用 struct.pack('>L', n) 打包為二進(jìn)制格式的四字節(jié)長(zhǎng)度的字符串打頭。

備注

Because portions of the configuration are passed through eval(), use of this function may open its users to a security risk. While the function only binds to a socket on localhost, and so does not accept connections from remote machines, there are scenarios where untrusted code could be run under the account of the process which calls listen(). Specifically, if the process calling listen() runs on a multi-user machine where users cannot trust each other, then a malicious user could arrange to run essentially arbitrary code in a victim user's process, simply by connecting to the victim's listen() socket and sending a configuration which runs whatever code the attacker wants to have executed in the victim's process. This is especially easy to do if the default port is used, but not hard even if a different port is used. To avoid the risk of this happening, use the verify argument to listen() to prevent unrecognised configurations from being applied.

在 3.4 版更改: 添加了 verify 參數(shù)。

備注

如果你希望將配置發(fā)送給未禁用現(xiàn)有日志記錄器的監(jiān)聽(tīng)器,你將需要使用 JSON 格式的配置,該格式將使用 dictConfig() 進(jìn)行配置。 此方法允許你在你發(fā)送的配置中將 disable_existing_loggers 指定為 False。

logging.config.stopListening()?

停止通過(guò)對(duì) listen() 的調(diào)用所創(chuàng)建的監(jiān)聽(tīng)服務(wù)器。 此函數(shù)的調(diào)用通常會(huì)先于在 listen() 的返回值上調(diào)用 join()。

Security considerations?

The logging configuration functionality tries to offer convenience, and in part this is done by offering the ability to convert text in configuration files into Python objects used in logging configuration - for example, as described in 用戶定義對(duì)象. However, these same mechanisms (importing callables from user-defined modules and calling them with parameters from the configuration) could be used to invoke any code you like, and for this reason you should treat configuration files from untrusted sources with extreme caution and satisfy yourself that nothing bad can happen if you load them, before actually loading them.

配置字典架構(gòu)?

描述日志記錄配置需要列出要?jiǎng)?chuàng)建的不同對(duì)象及它們之間的連接;例如,你可以創(chuàng)建一個(gè)名為 'console' 的處理器,然后名為 'startup' 的日志記錄器將可以把它的消息發(fā)送給 'console' 處理器。 這些對(duì)象并不僅限于 logging 模塊所提供的對(duì)象,因?yàn)槟氵€可以編寫你自己的格式化或處理器類。 這些類的形參可能還需要包括 sys.stderr 這樣的外部對(duì)象。 描述這些對(duì)象和連接的語(yǔ)法會(huì)在下面的 對(duì)象連接 中定義。

字典架構(gòu)細(xì)節(jié)?

傳給 dictConfig() 的字典必須包含以下的鍵:

  • version - 應(yīng)設(shè)為代表架構(gòu)版本的整數(shù)值。 目前唯一有效的值是 1,使用此鍵可允許架構(gòu)在繼續(xù)演化的同時(shí)保持向下兼容性。

所有其他鍵都是可選項(xiàng),但如存在它們將根據(jù)下面的描述來(lái)解讀。 在下面提到 'configuring dict' 的所有情況下,都將檢查它的特殊鍵 '()' 以確定是否需要自定義實(shí)例化。 如果需要,則會(huì)使用下面 用戶定義對(duì)象 所描述的機(jī)制來(lái)創(chuàng)建一個(gè)實(shí)例;否則,會(huì)使用上下文來(lái)確定要實(shí)例化的對(duì)象。

  • formatters - 對(duì)應(yīng)的值將是一個(gè)字典,其中每個(gè)鍵是一個(gè)格式器 ID 而每個(gè)值則是一個(gè)描述如何配置相應(yīng) Formatter 實(shí)例的字典。

    在配置字典中搜索以下可選鍵,這些鍵對(duì)應(yīng)于創(chuàng)建 Formatter 對(duì)象時(shí)傳入的參數(shù)。:

    • format

    • datefmt

    • style

    • validate (從版本 >=3.8 起)

    可選的 class 鍵指定格式化器類的名稱(形式為帶點(diǎn)號(hào)的模塊名和類名)。 實(shí)例化的參數(shù)與 Formatter 的相同,因此這個(gè)鍵對(duì)于實(shí)例化自定義的 Formatter 子類最為有用。 如果,替代類可能 會(huì)以擴(kuò)展和精簡(jiǎn)格式呈現(xiàn)異常回溯信息。 如果你的格式化器需要不同的或額外的配置鍵,你應(yīng)當(dāng)使用 用戶定義對(duì)象。

  • filters - 對(duì)應(yīng)的值將是一個(gè)字典,其中每個(gè)鍵是一個(gè)過(guò)濾器 ID 而每個(gè)值則是一個(gè)描述如何配置相應(yīng) Filter 實(shí)例的字典。

    將在配置字典中搜索鍵 name (默認(rèn)值為空字符串) 并且該鍵會(huì)被用于構(gòu)造 logging.Filter 實(shí)例。

  • handlers - 對(duì)應(yīng)的值將是一個(gè)字典,其中每個(gè)鍵是一個(gè)處理器 ID 而每個(gè)值則是一個(gè)描述如何配置相應(yīng) Handler 實(shí)例的字典。

    將在配置字典中搜索下列鍵:

    • class (強(qiáng)制)。 這是處理器類的完整限定名稱。

    • level (可選)。 處理器的級(jí)別。

    • formatter (可選)。 處理器所對(duì)應(yīng)格式化器的 ID。

    • filters (可選)。 由處理器所對(duì)應(yīng)過(guò)濾器的 ID 組成的列表。

      在 3.11 版更改: filters can take filter instances in addition to ids.

    所有 其他 鍵會(huì)被作為關(guān)鍵字參數(shù)傳遞給處理器類的構(gòu)造器。 例如,給定如下配置:

    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 的處理器會(huì)被實(shí)例化為 logging.StreamHandler,并使用 sys.stdout 作為下層流。 ID 為 file 的處理器會(huì)被實(shí)例化為 logging.handlers.RotatingFileHandler,并附帶關(guān)鍵字參數(shù) filename='logconfig.log', maxBytes=1024, backupCount=3

  • loggers - 對(duì)應(yīng)的值將是一個(gè)字典,其中每個(gè)鍵是一個(gè)日志記錄器名稱而每個(gè)值則是一個(gè)描述如何配置相應(yīng) Logger 實(shí)例的字典。

    將在配置字典中搜索下列鍵:

    • level (可選)。 日志記錄器的級(jí)別。

    • propagate (可選)。 日志記錄器的傳播設(shè)置。

    • filters (可選)。 由日志記錄器對(duì)應(yīng)過(guò)濾器的 ID 組成的列表。

      在 3.11 版更改: filters can take filter instances in addition to ids.

    • handlers (可選)。 由日志記錄器對(duì)應(yīng)處理器的 ID 組成的列表。

    指定的記錄器將根據(jù)指定的級(jí)別、傳播、過(guò)濾器和處理器來(lái)配置。

  • root - 這將成為根日志記錄器對(duì)應(yīng)的配置。 配置的處理方式將與所有日志記錄器一致,除了 propagate 設(shè)置將不可用之外。

  • incremental - 配置是否要被解讀為在現(xiàn)有配置上新增。 該值默認(rèn)為 False,這意味著指定的配置將以與當(dāng)前 fileConfig() API 所使用的相同語(yǔ)義來(lái)替代現(xiàn)有的配置。

    如果指定的值為 True,配置會(huì)按照 增量配置 部分所描述的方式來(lái)處理。

  • disable_existing_loggers - 是否要禁用任何現(xiàn)有的非根日志記錄器。 該設(shè)置對(duì)應(yīng)于 fileConfig() 中的同名形參。 如果省略,則此形參默認(rèn)為 True。 如果 incrementalTrue 則該省會(huì)被忽略。

增量配置?

為增量配置提供完全的靈活性是很困難的。 例如,由于過(guò)濾器和格式化器這樣的對(duì)象是匿名的,一旦完成配置,在增加配置時(shí)就不可能引用這些匿名對(duì)象。

此外,一旦完成了配置,在運(yùn)行時(shí)任意改變?nèi)罩居涗浧?、處理器、過(guò)濾器、格式化器的對(duì)象圖就不是很有必要;日志記錄器和處理器的詳細(xì)程度只需通過(guò)設(shè)置級(jí)別即可實(shí)現(xiàn)控制(對(duì)于日志記錄器則可設(shè)置傳播旗標(biāo))。 在多線程環(huán)境中以安全的方式任意改變對(duì)象圖也許會(huì)導(dǎo)致問(wèn)題;雖然并非不可能,但這樣做的好處不足以抵銷其所增加的實(shí)現(xiàn)復(fù)雜度。

這樣,當(dāng)配置字典的 incremental 鍵存在且為 True 時(shí),系統(tǒng)將完全忽略任何 formattersfilters 條目,并僅會(huì)處理 handlers 條目中的 level 設(shè)置,以及 loggersroot 條目中的 levelpropagate 設(shè)置。

使用配置字典中的值可讓配置以封存字典對(duì)象的形式通過(guò)線路傳送給套接字監(jiān)聽(tīng)器。 這樣,長(zhǎng)時(shí)間運(yùn)行的應(yīng)用程序的日志記錄的詳細(xì)程度可隨時(shí)間改變而無(wú)須停止并重新啟動(dòng)應(yīng)用程序。

對(duì)象連接?

該架構(gòu)描述了一組日志記錄對(duì)象 —— 日志記錄器、處理器、格式化器、過(guò)濾器 —— 它們?cè)趯?duì)象圖中彼此連接。 因此,該架構(gòu)需要能表示對(duì)象之間的連接。 例如,在配置完成后,一個(gè)特定的日志記錄器關(guān)聯(lián)到了一個(gè)特定的處理器。 出于討論的目的,我們可以說(shuō)該日志記錄器代表兩者間連接的源頭,而處理器則代表對(duì)應(yīng)的目標(biāo)。 當(dāng)然在已配置對(duì)象中這是由包含對(duì)處理器的引用的日志記錄器來(lái)代表的。 在配置字典中,這是通過(guò)給每個(gè)目標(biāo)對(duì)象一個(gè) ID 來(lái)無(wú)歧義地標(biāo)識(shí)它,然后在源頭對(duì)象中使用該 ID 來(lái)實(shí)現(xiàn)的。

因此,舉例來(lái)說(shuō),考慮以下 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 是因?yàn)樗目勺x性比表示字典的等價(jià) Python 源碼形式更好。)

日志記錄器 ID 就是日志記錄器的名稱,它會(huì)在程序中被用來(lái)獲取對(duì)日志記錄器的引用,例如 foo.bar.baz。 格式化器和過(guò)濾器的 ID 可以是任意字符串值 (例如上面的 brief, precise) 并且它們是瞬態(tài)的,因?yàn)樗鼈儍H對(duì)處理配置字典有意義并會(huì)被用來(lái)確定對(duì)象之間的連接,而當(dāng)配置調(diào)用完成時(shí)不會(huì)在任何地方保留。

上面的代碼片段指明名為 foo.bar.baz 的日志記錄器應(yīng)當(dāng)關(guān)聯(lián)到兩個(gè)處理器,它們的 ID 是 h1h2。 h1 的格式化器的 ID 是 brief,而 h2 的格式化器的 ID 是 precise。

用戶定義對(duì)象?

此架構(gòu)支持用戶定義對(duì)象作為處理器、過(guò)濾器和格式化器。 (日志記錄器的不同實(shí)例不需要具有不同類型,因此這個(gè)配置架構(gòu)并不支持用戶定義日志記錄器類。)

要配置的對(duì)象是由字典描述的,其中包含它們的配置詳情。 在某些地方,日志記錄系統(tǒng)將能夠從上下文中推斷出如何實(shí)例化一個(gè)對(duì)象,但是當(dāng)要實(shí)例化一個(gè)用戶自定義對(duì)象時(shí),系統(tǒng)將不知道要如何做。 為了提供用戶自定義對(duì)象實(shí)例化的完全靈活性,用戶需要提供一個(gè)‘工廠’函數(shù) —— 即在調(diào)用時(shí)傳入配置字典并返回實(shí)例化對(duì)象的可調(diào)用對(duì)象。 這是用一個(gè)通過(guò)特殊鍵 '()' 來(lái)訪問(wèn)的工廠函數(shù)的絕對(duì)導(dǎo)入路徑來(lái)標(biāo)示的。 下面是一個(gè)實(shí)際的例子:

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 代碼片段定義了三個(gè)格式化器。 第一個(gè)的 ID 為 brief,是帶有特殊格式字符串的標(biāo)準(zhǔn) logging.Formatter 實(shí)例。 第二個(gè)的 ID 為 default,具有更長(zhǎng)的格式同時(shí)還顯式地定義了時(shí)間格式,并將最終實(shí)例化一個(gè)帶有這兩個(gè)格式字符串的 logging.Formatter。 以 Python 源代碼形式顯示的 briefdefault 格式化器分別具有下列配置子字典:

{
  'format' : '%(message)s'
}

和:

{
  'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
  'datefmt' : '%Y-%m-%d %H:%M:%S'
}

并且由于這些字典不包含特殊鍵 '()',實(shí)例化方式是從上下文中推斷出來(lái)的:結(jié)果會(huì)創(chuàng)建標(biāo)準(zhǔn)的 logging.Formatter 實(shí)例。 第三個(gè)格式器的 ID 為 custom,對(duì)應(yīng)配置子字典為:

{
  '()' : 'my.package.customFormatterFactory',
  'bar' : 'baz',
  'spam' : 99.9,
  'answer' : 42
}

并且它包含特殊鍵 '()',這意味著需要用戶自定義實(shí)例化方式。 在此情況下,將使用指定的工廠可調(diào)用對(duì)象。 如果它本身就是一個(gè)可調(diào)用對(duì)象則將被直接使用 —— 否則如果你指定了一個(gè)字符串(如這個(gè)例子所示)則將使用正常的導(dǎo)入機(jī)制來(lái)定位實(shí)例的可調(diào)用對(duì)象。 調(diào)用該可調(diào)用對(duì)象將傳入配置子字典中 剩余的 條目作為關(guān)鍵字參數(shù)。 在上面的例子中,調(diào)用將預(yù)期返回 ID 為 custom 的格式化器:

my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)

'()' 用作特殊鍵是因?yàn)樗皇且粋€(gè)有效的關(guān)鍵字形參名稱,這樣就不會(huì)與調(diào)用中使用的關(guān)鍵字參數(shù)發(fā)生沖突。 '()' 還被用作表明對(duì)應(yīng)值為可調(diào)用對(duì)象的助記符。

在 3.11 版更改: The filters member of handlers and loggers can take filter instances in addition to ids.

訪問(wèn)外部對(duì)象?

有時(shí)一個(gè)配置需要引用配置以外的對(duì)象,例如 sys.stderr。 如果配置字典是使用 Python 代碼構(gòu)造的,這會(huì)很直觀,但是當(dāng)配置是通過(guò)文本文件(例如 JSON, YAML)提供的時(shí)候就會(huì)引發(fā)問(wèn)題。 在一個(gè)文本文件中,沒(méi)有將 sys.stderr 與字符串字面值 'sys.stderr' 區(qū)分開(kāi)來(lái)的標(biāo)準(zhǔn)方式。 為了實(shí)現(xiàn)這種區(qū)分,配置系統(tǒng)會(huì)在字符串值中查找規(guī)定的特殊前綴并對(duì)其做特殊處理。 例如,如果在配置中將字符串字面值 'ext://sys.stderr' 作為一個(gè)值來(lái)提供,則 ext:// 將被去除而該值的剩余部分將使用正常導(dǎo)入機(jī)制來(lái)處理。

此類前綴的處理方式類似于協(xié)議處理:存在一種通用機(jī)制來(lái)查找與正則表達(dá)式 ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$ 相匹配的前綴,如果識(shí)別出了 prefix,則 suffix 會(huì)以與前綴相對(duì)應(yīng)的方式來(lái)處理并且處理的結(jié)果將替代原字符串值。 如果未識(shí)別出前綴,則原字符串將保持不變。

訪問(wèn)內(nèi)部對(duì)象?

除了外部對(duì)象,有時(shí)還需要引用配置中的對(duì)象。 這將由配置系統(tǒng)針對(duì)它所了解的內(nèi)容隱式地完成。 例如,在日志記錄器或處理器中表示 level 的字符串值 'DEBUG' 將被自動(dòng)轉(zhuǎn)換為值 logging.DEBUG,而 handlers, filtersformatter 條目將接受一個(gè)對(duì)象 ID 并解析為適當(dāng)?shù)哪繕?biāo)對(duì)象。

但是,對(duì)于 logging 模塊所不了解的用戶自定義對(duì)象則需要一種更通用的機(jī)制。 例如,考慮 logging.handlers.MemoryHandler,它接受一個(gè) target 參數(shù)即其所委托的另一個(gè)處理器。 由于系統(tǒng)已經(jīng)知道存在該類,因而在配置中,給定的 target 只需為相應(yīng)目標(biāo)處理器的的對(duì)象 ID 即可,而系統(tǒng)將根據(jù)該 ID 解析出處理器。 但是,如果用戶定義了一個(gè)具有 alternate 處理器的 my.package.MyHandler,則配置程序?qū)⒉恢?alternate 指向的是一個(gè)處理器。 為了應(yīng)對(duì)這種情況,通用解析系統(tǒng)允許用戶指定:

handlers:
  file:
    # configuration of file handler goes here

  custom:
    (): my.package.MyHandler
    alternate: cfg://handlers.file

字符串字面值 'cfg://handlers.file' 將按照與 ext:// 前綴類似的方式被解析為結(jié)果字符串,但查找操作是在配置自身而不是在導(dǎo)入命名空間中進(jìn)行。 該機(jī)制允許按點(diǎn)號(hào)或按索引來(lái)訪問(wèn),與 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 將解析為具有 email 鍵的 handlers 字典中的字典,依此類推。 字符串 'cfg://handlers.email.toaddrs[1] 將解析為 'dev_team@domain.tld' 而字符串 'cfg://handlers.email.toaddrs[0]' 將解析為值 'support_team@domain.tld'。 subject 值 可以使用 'cfg://handlers.email.subject' 或者等價(jià)的 'cfg://handlers.email[subject]' 來(lái)訪問(wèn)。 后一種形式僅在鍵包含空格或非字母類數(shù)字類字符的情況下才需要使用。 如果一個(gè)索引僅由十進(jìn)制數(shù)碼構(gòu)成,則將嘗試使用相應(yīng)的整數(shù)值來(lái)訪問(wèn),如果有必要?jiǎng)t將回退為字符串值。

給定字符串 cfg://handlers.myhandler.mykey.123,這將解析為 config_dict['handlers']['myhandler']['mykey']['123']。 如果字符串被指定為 cfg://handlers.myhandler.mykey[123],系統(tǒng)將嘗試從 config_dict['handlers']['myhandler']['mykey'][123] 中提取值,并在嘗試失敗時(shí)回退為 config_dict['handlers']['myhandler']['mykey']['123']。

導(dǎo)入解析與定制導(dǎo)入器?

導(dǎo)入解析默認(rèn)使用內(nèi)置的 __import__() 函數(shù)來(lái)執(zhí)行導(dǎo)入。 你可能想要將其替換為你自己的導(dǎo)入機(jī)制:如果是這樣的話,你可以替換 DictConfigurator 或其超類 BaseConfigurator 類的 importer 屬性。 但是你必須小心謹(jǐn)慎,因?yàn)楹瘮?shù)是從類中通過(guò)描述器方式來(lái)訪問(wèn)的。 如果你使用 Python 可調(diào)用對(duì)象來(lái)執(zhí)行導(dǎo)入,并且你希望在類層級(jí)而不是在實(shí)例層級(jí)上定義它,則你需要用 staticmethod() 來(lái)裝飾它。 例如:

from importlib import import_module
from logging.config import BaseConfigurator

BaseConfigurator.importer = staticmethod(import_module)

如果你是在一個(gè)配置器的 實(shí)例 上設(shè)置導(dǎo)入可調(diào)用對(duì)象則你不需要用 staticmethod() 來(lái)裝飾。

配置文件格式?

fileConfig() 所能理解的配置文件格式是基于 configparser 功能的。 該文件必須包含 [loggers], [handlers][formatters] 等小節(jié),它們通過(guò)名稱來(lái)標(biāo)識(shí)文件中定義的每種類型的實(shí)體。 對(duì)于每個(gè)這樣的實(shí)體,都有單獨(dú)的小節(jié)來(lái)標(biāo)識(shí)實(shí)體的配置方式。 因此,對(duì)于 [loggers] 小節(jié)中名為 log01 的日志記錄器,相應(yīng)的配置詳情保存在 [logger_log01] 小節(jié)中。 類似地,對(duì)于 [handlers] 小節(jié)中名為 hand01 的處理器,其配置將保存在名為 [handler_hand01] 的小節(jié)中,而對(duì)于 [formatters] 小節(jié)中名為 form01 的格式化器,其配置將在名為 [formatter_form01] 的小節(jié)中指定。 根日志記錄器的配置必須在名為 [logger_root] 的小節(jié)中指定。

備注

fileConfig() API 比 dictConfig() API 更舊因而沒(méi)有提供涵蓋日志記錄特定方面的功能。 例如,你無(wú)法配置 Filter 對(duì)象,該對(duì)象使用 fileConfig() 提供超出簡(jiǎn)單整數(shù)級(jí)別的消息過(guò)濾功能。 如果你想要在你的日志記錄配置中包含 Filter 的實(shí)例,你將必須使用 dictConfig()。 請(qǐng)注意未來(lái)還將向 dictConfig() 添加對(duì)配置功能的強(qiáng)化,因此值得考慮在方便的時(shí)候轉(zhuǎn)換到這個(gè)新 API。

在文件中這些小節(jié)的例子如下所示。

[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

根日志記錄器必須指定一個(gè)級(jí)別和一個(gè)處理器列表。 根日志小節(jié)的例子如下所示。

[logger_root]
level=NOTSET
handlers=hand01

The level entry can be one of DEBUG, INFO, WARNING, ERROR, CRITICAL or NOTSET. For the root logger only, NOTSET means that all messages will be logged. Level values are evaluated in the context of the logging package's namespace.

handlers 條目是以逗號(hào)分隔的處理器名稱列表,它必須出現(xiàn)于 [handlers] 小節(jié)并且在配置文件中有相應(yīng)的小節(jié)。

對(duì)于根日志記錄器以外的日志記錄器,還需要某些附加信息。 下面的例子演示了這些信息。

[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser

levelhandlers 條目的解釋方式與根日志記錄器的一致,不同之處在于如果一個(gè)非根日志記錄器的級(jí)別被指定為 NOTSET,則系統(tǒng)會(huì)咨詢更高層級(jí)的日志記錄器來(lái)確定該日志記錄器的有效級(jí)別。 propagate 條目設(shè)為 1 表示消息必須從此日志記錄器傳播到更高層級(jí)的處理器,設(shè)為 0 表示消息 不會(huì) 傳播到更高層級(jí)的處理器。 qualname 條目是日志記錄器的層級(jí)通道名稱,也就是應(yīng)用程序獲取日志記錄器所用的名稱。

指定處理器配置的小節(jié)說(shuō)明如下。

[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)

class 條目指明處理器的類(由 logging 包命名空間中的 eval() 來(lái)確定)。 level 會(huì)以與日志記錄器相同的方式來(lái)解讀,NOTSET 會(huì)被視為表示‘記錄一切消息’。

formatter 條目指明此處理器的格式化器的鍵名稱。 如為空白,則會(huì)使用默認(rèn)的格式化器 (logging._defaultFormatter)。 如果指定了名稱,則它必須出現(xiàn)于 [formatters] 小節(jié)并且在配置文件中有相應(yīng)的小節(jié)。

The args entry, when evaluated in the context of the logging package's namespace, is the list of arguments to the constructor for the handler class. Refer to the constructors for the relevant handlers, or to the examples below, to see how typical entries are constructed. If not provided, it defaults to ().

The optional kwargs entry, when evaluated in the context of the logging package's namespace, is the keyword argument dict to the constructor for the handler class. If not provided, it defaults to {}.

[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}

指定格式化器配置的小節(jié)說(shuō)明如下。

[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s
datefmt=
style=%
validate=True
class=logging.Formatter

用于格式化器配置的參數(shù)與字典規(guī)范 格式化器部分 中的鍵相同。

備注

由于如上所述使用了 eval(),因此使用 listen() 通過(guò)套接字來(lái)發(fā)送和接收配置會(huì)導(dǎo)致潛在的安全風(fēng)險(xiǎn)。 此風(fēng)險(xiǎn)僅限于相互間沒(méi)有信任的多個(gè)用戶在同一臺(tái)機(jī)器上運(yùn)行代碼的情況;請(qǐng)參閱 listen() 了解更多信息。

參見(jiàn)

模塊 logging

日志記錄模塊的 API 參考。

logging.handlers 模塊

日志記錄模塊附帶的有用處理器。