15.8. logging.config — 日志配置 — Python 文档
15.8. 日志配置文件 — 日志配置
重要的
此页面仅包含参考信息。 有关教程,请参阅
源代码: :source:`Lib/logging/config.py`
本节介绍配置日志模块的API。
15.8.1. 配置功能
以下函数配置日志记录模块。 它们位于 logging.config 模块中。 它们的使用是可选的——您可以使用这些函数或通过调用主 API(在 logging 本身中定义)并定义在 logging 或logging.handlers。
- logging.config.dictConfig(config)
从字典中获取日志记录配置。 这个字典的内容在下面的配置字典架构中描述。
如果在配置过程中遇到错误,此函数将引发
ValueError
、TypeError
、AttributeError
或ImportError
以及适当的描述性消息。 以下是会引发错误的条件列表(可能不完整):A
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() 可以完全按照默认的、未自定义的状态调用。2.7 版中的新功能。
- logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True)
从名为 fname 的
configparser
格式文件中读取日志记录配置。 文件格式应如配置文件格式中所述。 可以从应用程序多次调用此函数,从而允许最终用户从各种预装配置中进行选择(如果开发人员提供了一种机制来呈现选择并加载所选配置)。- 参数
defaults – 可以在此参数中指定要传递给 ConfigParser 的默认值。
disable_existing_loggers – 如果指定为
False
,则在进行此调用时存在的记录器保持启用状态。 默认值为True
,因为这会以向后兼容的方式启用旧行为。 此行为是禁用任何现有记录器,除非它们或其祖先在日志记录配置中明确命名。
2.6 版更改: 添加了
disable_existing_loggers
关键字参数。 以前,现有的记录器 总是 禁用。
- logging.config.listen(port=DEFAULT_LOGGING_CONFIG_PORT)
在指定端口上启动套接字服务器,并侦听新配置。 如果未指定端口,则使用模块的默认
DEFAULT_LOGGING_CONFIG_PORT
。 日志配置将作为适合由 fileConfig() 处理的文件发送。 返回一个 Thread 实例,您可以在该实例上调用 start() 来启动服务器,并且您可以在适当的时候 join()。 要停止服务器,请调用 stopListening()。要将配置发送到套接字,请读入配置文件并将其作为字节字符串发送到套接字,前面是使用
struct.pack('>L', n)
以二进制形式打包的四字节长度字符串。
15.8.2. 配置字典架构
描述日志配置需要列出要创建的各种对象以及它们之间的连接; 例如,您可以创建一个名为“console”的处理程序,然后说名为“startup”的记录器将其消息发送到“console”处理程序。 这些对象不限于 logging 模块提供的对象,因为您可能会编写自己的格式化程序或处理程序类。 这些类的参数可能还需要包含外部对象,例如 sys.stderr
。 描述这些对象和连接的语法在下面的 对象连接 中定义。
15.8.2.1. 字典架构详细信息
传递给 dictConfig() 的字典必须包含以下键:
- version - 设置为代表模式版本的整数值。 目前唯一有效的值是 1,但是拥有这个键可以让架构在保持向后兼容性的同时发展。
所有其他键都是可选的,但如果存在,它们将按如下所述进行解释。 在下面提到“配置字典”的所有情况下,将检查特殊的 '()'
键以查看是否需要自定义实例化。 如果是这样,则使用下面用户定义对象中描述的机制来创建实例; 否则,上下文用于确定要实例化的内容。
formatters - 对应的值将是一个字典,其中每个键是一个格式化程序 id,每个值是一个描述如何配置相应 Formatter 实例的字典。
在配置字典中搜索键
format
和datefmt
(默认为None
),这些用于构建 Formatter 实例。filters - 对应的值将是一个字典,其中每个键是一个过滤器 ID,每个值是一个描述如何配置相应过滤器实例的字典。
在配置字典中搜索键
name
(默认为空字符串),这用于构造 logging.Filter 实例。handlers - 对应的值将是一个 dict,其中每个键是一个处理程序 ID,每个值是一个描述如何配置相应 Handler 实例的 dict。
在配置字典中搜索以下键:
class
(强制)。 这是处理程序类的完全限定名称。level
(可选)。 处理程序的级别。formatter
(可选)。 此处理程序的格式化程序的 ID。filters
(可选)。 此处理程序的过滤器 ID 列表。
所有 other 键都作为关键字参数传递给处理程序的构造函数。 例如,给定片段:
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 列表。handlers
(可选)。 此记录器的处理程序的 id 列表。
指定的记录器将根据指定的级别、传播、过滤器和处理程序进行配置。
root - 这将是根记录器的配置。 除了
propagate
设置不适用之外,配置的处理与任何记录器一样。incremental - 配置是否被解释为现有配置的增量。 此值默认为
False
,这意味着指定的配置将替换现有配置,其语义与现有 fileConfig() API 使用的语义相同。如果指定的值为
True
,则按照 增量配置 部分中的描述处理配置。disable_existing_loggers - 是否要禁用任何现有记录器。 此设置反映了 fileConfig() 中的同名参数。 如果不存在,该参数默认为
True
。 如果 incremental 是True
,则忽略此值。
15.8.2.2. 增量配置
很难为增量配置提供完全的灵活性。 例如,由于过滤器和格式化程序等对象是匿名的,因此一旦设置了配置,在扩充配置时就不可能引用此类匿名对象。
此外,一旦配置被设置,在运行时任意改变记录器、处理程序、过滤器、格式化程序的对象图是没有说服力的。 记录器和处理程序的详细程度可以通过设置级别(以及在记录器的情况下,传播标志)来控制。 在多线程环境中,以安全的方式任意更改对象图是有问题的; 虽然并非不可能,但其带来的好处不值得为实现增加复杂性。
因此,当配置字典的 incremental
键存在且为 True
时,系统将完全忽略任何 formatters
和 filters
条目,并且只处理handlers
条目中的 level
设置,以及 loggers
和 root
条目中的 level
和 propagate
设置.
在配置字典中使用一个值可以让配置作为腌制字典通过网络发送到套接字侦听器。 因此,长时间运行的应用程序的日志记录详细程度可以随着时间的推移而改变,而无需停止和重新启动应用程序。
15.8.2.3. 对象连接
该模式描述了一组日志对象——记录器、处理程序、格式化程序、过滤器——它们在对象图中相互连接。 因此,模式需要表示对象之间的连接。 例如,假设一旦配置,一个特定的记录器就附加了一个特定的处理程序。 出于本次讨论的目的,我们可以说记录器代表两者之间的连接的源,而处理程序代表目标。 当然,在配置的对象中,这由持有对处理程序的引用的记录器表示。 在配置字典中,这是通过给每个目标对象一个明确标识它的 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
。 Formatters 和 Filters 的 id 可以是任何字符串值(例如上面的 brief
、precise
)并且它们是暂时的,因为它们仅对处理配置字典有意义并用于确定连接对象之间,并且在配置调用完成后不会在任何地方持久化。
上面的代码片段表明名为 foo.bar.baz
的记录器应该附加两个处理程序,它们由处理程序 ID h1
和 h2
描述。 h1
的格式化程序是由id brief
描述的,h2
的格式化程序是由id precise
描述的。
15.8.2.4. 用户定义对象
该架构支持用于处理程序、过滤器和格式化程序的用户定义对象。 (对于不同的实例,记录器不需要有不同的类型,所以这个配置模式不支持用户定义的记录器类。)
要配置的对象由详细描述其配置的字典描述。 在某些地方,日志系统将能够从上下文推断对象将如何实例化,但是当要实例化用户定义的对象时,系统将不知道如何执行此操作。 为了为用户定义的对象实例化提供完全的灵活性,用户需要提供一个“工厂”——一个可调用的,它被一个配置字典调用并返回实例化的对象。 这是通过在特殊键 '()'
下提供到工厂的绝对导入路径来表示的。 这是一个具体的例子:
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
}
并且它包含特殊键 '()'
,这意味着需要用户定义的实例化。 在这种情况下,将使用指定的工厂调用。 如果它是一个实际的可调用对象,它将被直接使用 - 否则,如果您指定一个字符串(如示例中所示),则将使用正常的导入机制来定位实际的可调用对象。 callable 将使用配置子字典中的 剩余 项作为关键字参数来调用。 在上面的例子中,id 为 custom
的格式化程序将被假定为由调用返回:
my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)
键 '()'
已被用作特殊键,因为它不是有效的关键字参数名称,因此不会与调用中使用的关键字参数的名称发生冲突。 '()'
也可以作为对应值是可调用的助记符。
15.8.2.5. 访问外部对象
有时配置需要引用配置外部的对象,例如 sys.stderr
。 如果配置字典是使用 Python 代码构建的,这很简单,但是当配置通过文本文件(例如 JSON、YAML)。 在文本文件中,没有标准方法可以将 sys.stderr
与文字字符串 'sys.stderr'
区分开来。 为了便于区分,配置系统会在字符串值中查找某些特殊前缀并对其进行特殊处理。 例如,如果文本字符串 'ext://sys.stderr'
在配置中作为一个值提供,那么 ext://
将被剥离,其余的值将使用正常的导入机制进行处理。
此类前缀的处理方式类似于协议处理:有一种通用机制来查找与正则表达式 ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$
匹配的前缀,如果识别出 prefix
,则 [ X219X] 以前缀依赖的方式处理,处理结果替换字符串值。 如果前缀未被识别,则字符串值将保持原样。
15.8.2.6. 访问内部对象
除了外部对象,有时还需要引用配置中的对象。 这将由配置系统为它知道的事情隐式完成。 例如,记录器或处理程序中 level
的字符串值 'DEBUG'
将自动转换为值 logging.DEBUG
,而 handlers
、filters
和 formatter
条目将采用对象 ID 并解析为适当的目标对象。
但是,对于 logging 模块不知道的用户定义对象,需要更通用的机制。 例如,考虑 logging.handlers.MemoryHandler,它接受一个 target
参数,这是另一个要委托给的处理程序。 既然系统已经知道这个类,那么在配置中,给定的target
只要是相关目标handler的object id,系统就会根据id解析到handler。 但是,如果用户定义了具有 alternate
处理程序的 my.package.MyHandler
,配置系统将不知道 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
将解析为 email
键的字典X162X] dict,依此类推。 字符串 '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']
。
15.8.2.7. 导入分辨率和自定义导入器
默认情况下,导入分辨率使用内置的 __import__() 函数进行导入。 您可能想用自己的导入机制替换它:如果是这样,您可以替换 DictConfigurator
或其超类 BaseConfigurator
类的 importer
属性。 但是,由于通过描述符从类访问函数的方式,您需要小心。 如果您使用 Python 可调用来执行导入,并且希望在类级别而不是实例级别定义它,则需要使用 staticmethod() 将其包装起来。 例如:
from importlib import import_module
from logging.config import BaseConfigurator
BaseConfigurator.importer = staticmethod(import_module)
如果您在配置器 实例 上设置可调用的导入,则不需要用 staticmethod() 包装。
15.8.3. 配置文件格式
fileConfig() 理解的配置文件格式基于 configparser
功能。 该文件必须包含名为 [loggers]
、[handlers]
和 [formatters]
的部分,它们通过名称标识文件中定义的每种类型的实体。 对于每个这样的实体,都有一个单独的部分来标识该实体的配置方式。 因此,对于 [loggers]
部分中名为 log01
的记录器,相关配置详细信息保存在 [logger_log01]
部分中。 类似地,[handlers]
节中名为 hand01
的处理程序将其配置保存在名为 [handler_hand01]
的节中,而 [formatters]
部分将在名为 [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
包的命名空间的上下文中是 eval()。
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
被认为意味着“记录一切”。
在 2.6 版中更改: 添加了对将处理程序的类解析为带点的模块和类名的支持。
formatter
条目指示此处理程序的格式化程序的键名称。 如果为空,则使用默认格式化程序 (logging._defaultFormatter
)。 如果指定了名称,它必须出现在 [formatters]
部分中,并且在配置文件中有相应的部分。
args
条目,当 eval() 在 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')
[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')
指定格式化程序配置的部分由以下代表。
[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s
datefmt=
class=logging.Formatter
format
条目是整体格式字符串,datefmt
条目是 strftime()
兼容的日期/时间格式字符串。 如果为空,则包替换 ISO8601 格式日期/时间,这几乎等同于指定日期格式字符串 '%Y-%m-%d %H:%M:%S'
。 ISO8601 格式还指定了毫秒,这些毫秒会附加到使用上述格式字符串的结果中,并带有逗号分隔符。 ISO8601 格式的示例时间是 2003-01-23 00:29:50,411
。
class
条目是可选的。 它指示格式化程序类的名称(作为带点的模块和类名。)此选项对于实例化 Formatter 子类很有用。 Formatter 的子类可以以扩展或压缩格式呈现异常回溯。