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
模块日志模块附带的有用的处理器。