logging.config ---日志配置¶
本节介绍用于配置日志模块的API。
配置功能¶
以下功能配置日志记录模块。它们位于 logging.config 模块。它们的使用是可选的——您可以使用这些函数或通过调用主API(在中定义)来配置日志模块。 logging 以及定义在 logging 或 logging.handlers .
- logging.config.dictConfig(config)¶
从字典获取日志配置。本词典的内容在 配置字典架构 下面。
如果在配置过程中遇到错误,此函数将引发
ValueError,TypeError,AttributeError或ImportError带有适当的描述性信息。以下是将引发错误的条件(可能不完整)列表:A
level它不是字符串,或者它不是与实际日志记录级别不对应的字符串。A
propagate不是布尔值的值。没有相应目标的ID。
在增量调用期间发现不存在的处理程序ID。
记录器名称无效。
无法解析为内部或外部对象。
解析由执行
DictConfigurator类,其构造函数传递用于配置的字典,并具有configure()方法。这个logging.config模块具有可调用属性dictConfigClass初始设置为DictConfigurator. 您可以替换dictConfigClass用你自己的一个合适的实现。dictConfig()调用dictConfigClass传递指定的字典,然后调用configure()返回的对象上的方法以使配置生效::def dictConfig(config): dictConfigClass(config).configure()
例如,子类
DictConfigurator可以调用DictConfigurator.__init__()在它自己的__init__(),然后设置自定义前缀,这些前缀将在后面的configure()调用。dictConfigClass将绑定到这个新的子类,然后dictConfig()可以完全按照默认的非自定义状态调用。3.2 新版功能.
- logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True)¶
从中读取日志配置
configparser格式化文件。文件格式应如中所述。 配置文件格式 . 可以从应用程序中多次调用此函数,从而允许最终用户从各种预屏蔽配置中进行选择(如果开发人员提供了一种呈现选择并加载所选配置的机制)。- 参数
fname -- 文件名、类似文件的对象或派生自
RawConfigParser. 如果ARawConfigParser-已传递派生实例,它将按原样使用。否则,AConfigparser是实例化的,它从传入的对象中读取配置fname. 如果有readline()方法,假定它是一个类似文件的对象,并使用read_file();否则,假定它是一个文件名并传递给read().defaults -- 可以在此参数中指定要传递给configparser的默认值。
disable_existing_loggers -- 如果指定为
False,当进行此调用时存在的记录器保持启用状态。默认值为True因为这以向后兼容的方式启用了旧的行为。此行为用于禁用任何现有的非根记录器,除非它们或其祖先在日志配置中被显式命名。
在 3.4 版更改: 子类的实例
RawConfigParser现在被接受为fname. 这有助于:使用一个配置文件,其中日志配置只是整个应用程序配置的一部分。
使用从文件中读取的配置,然后由使用应用程序修改(例如,基于命令行参数或运行时环境的其他方面),然后再传递给
fileConfig.
- logging.config.listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)¶
在指定端口上启动套接字服务器,并侦听新配置。如果没有指定端口,则模块的默认值为
DEFAULT_LOGGING_CONFIG_PORT使用。日志配置将作为适合由处理的文件发送dictConfig()或fileConfig(). 返回AThread可以调用的实例start()启动服务器,您可以join()在适当的时候。要停止服务器,请致电stopListening().这个
verify参数(如果指定)应为可调用参数,该参数应验证通过套接字接收的字节是否有效并应进行处理。这可以通过对通过套接字发送的内容进行加密和/或签名来实现,这样verifyCallable可以执行签名验证和/或解密。这个verify使用单个参数调用Callable(可调用),即通过套接字接收的字节数,并应返回要处理的字节数,或者None以指示应丢弃字节。返回的字节可以与传入的字节相同(例如,仅在完成验证时),也可以完全不同(可能是在执行解密时)。要将配置发送到套接字,请读取配置文件并将其作为一个字节序列发送到套接字,该字节序列前面是一个以二进制形式打包的四字节长度字符串,使用
struct.pack('>L', n).注解
因为部分配置是通过
eval(),使用此功能可能会给用户带来安全风险。而函数只绑定到上的套接字localhost,因此不接受来自远程计算机的连接,在某些情况下,不受信任的代码可以在调用的进程的帐户下运行。listen(). 具体来说,如果进程调用listen()在多用户计算机上运行,在多用户计算机上,用户不能相互信任,那么恶意用户只需连接到受害者的进程,就可以安排在受害者的进程中运行基本上任意的代码。listen()套接字并发送一个配置,该配置运行攻击者希望在受害者进程中执行的任何代码。这在使用默认端口时特别容易,但即使使用不同的端口也不难)。为了避免发生这种情况的风险,请使用verify参数listen()以防止应用未识别的配置。在 3.4 版更改: 这个
verify已添加参数。注解
如果要向侦听器发送不禁用现有记录器的配置,则需要为配置使用JSON格式,该格式将使用
dictConfig()用于配置。此方法允许您指定disable_existing_loggers作为False在您发送的配置中。
配置字典架构¶
描述日志配置需要列出要创建的各种对象以及它们之间的连接;例如,您可以创建一个名为“console”的处理程序,然后说名为“startup”的记录器将其消息发送到“console”处理程序。这些对象不限于 logging 模块,因为您可以编写自己的格式化程序或处理程序类。这些类的参数可能还需要包括外部对象,例如 sys.stderr . 描述这些对象和连接的语法在 对象连接 下面。
字典架构详细信息¶
字典传给 dictConfig() 必须包含以下键:
版本 -设置为表示架构版本的整数值。目前唯一有效的值是1,但是拥有这个键允许模式在保持向后兼容性的同时发展。
所有其他键都是可选的,但如果存在,它们将按下面的说明进行解释。在下面提到“配置dict”的所有情况下,都将检查其是否具有 '()' 键查看是否需要自定义实例化。如果是这样,则 用户定义的对象 下面用于创建实例;否则,上下文用于确定要实例化的内容。
formatters -相应的值将是一个dict,其中每个键都是格式化程序ID,每个值都是一个dict,描述如何配置相应的
Formatter实例。在配置字典中搜索与传递的参数相对应的以下可选键,以创建
Formatter对象:formatdatefmtstylevalidate(从版本>=3.8开始)
可选的
class键指示格式化程序类的名称(以虚线模块和类名表示)。实例化参数与Formatter,因此,此键对于实例化的自定义子类最有用Formatter。例如,Alternative类可能以扩展或压缩格式显示异常回溯。如果格式化程序需要不同的或额外的配置键,则应使用 用户定义的对象 。过滤器 -相应的值将是一个dict,其中每个键都是一个过滤器ID,每个值都是一个dict,描述如何配置相应的过滤器实例。
在配置dict中搜索键
name(默认为空字符串),它用于构造logging.Filter实例。处理程序 -对应的值将是一个dict,其中每个键都是一个处理程序ID,每个值都是一个dict,描述如何配置对应的处理程序实例。
在配置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 -对应的值将是一个dict,其中每个键都是一个记录器名称,每个值都是一个dict,描述如何配置对应的记录器实例。
在配置dict中搜索以下键:
level(可选)。记录器的级别。propagate(可选)。记录器的传播设置。filters(可选)。此记录器的筛选器ID列表。handlers(可选)。此记录器处理程序的ID列表。
将根据指定的级别、传播、筛选器和处理程序配置指定的记录器。
root -这将是根记录器的配置。配置的处理将与任何记录器相同,除了
propagate设置将不适用。增量 -是否将配置解释为对现有配置的增量。此值默认为
False,这意味着指定的配置使用与现有配置相同的语义替换现有配置。fileConfig()应用程序编程接口。如果指定值为
True,配置将按照上一节中的说明进行处理。 增量配置 .disable_existing_loggers -是否要禁用任何现有的非根记录器。此设置在中镜像相同名称的参数
fileConfig(). 如果不存在,则此参数默认为True. 如果 增量 是True.
增量配置¶
很难为增量配置提供完全的灵活性。例如,由于过滤器和格式化程序等对象是匿名的,因此一旦设置了配置,就不可能在扩充配置时引用此类匿名对象。
此外,在运行时,一旦设置了一个配置,就没有一个令人信服的案例可以随意更改记录器、处理程序、过滤器、格式化程序的对象图;记录器和处理程序的冗长性可以通过设置级别来控制(对于记录器,还可以通过传播标志来控制)。在多线程环境中,以安全的方式随意更改对象图是有问题的;虽然这并非不可能,但其带来的好处并不值得在实现中增加复杂性。
因此,当 incremental 配置dict的键存在并且是 True ,系统将完全忽略 formatters 和 filters 并只处理 level 中的设置 handlers 条目,以及 level 和 propagate 中的设置 loggers 和 root 条目。
在配置dict中使用一个值,可以将配置作为泡菜dict通过线路发送到套接字侦听器。因此,长时间运行的应用程序的日志记录冗长性可以随着时间而改变,而无需停止和重新启动应用程序。
对象连接¶
该模式描述了一组记录对象——记录器、处理程序、格式化程序、过滤器——它们在对象图中相互连接。因此,模式需要表示对象之间的连接。例如,假设配置后,特定的记录器将特定的处理程序附加到它上。为了讨论这个问题,我们可以说记录器代表两个连接的源,而处理程序代表两个连接的目的。当然,在配置的对象中,这由保存对处理程序的引用的记录器表示。在配置dict中,这是通过给每个目标对象一个明确标识它的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 是用身份证描述的吗 brief 和格式化程序 h2 是用身份证描述的吗 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片段定义了三个格式化程序。第一个,带身份证 brief 是一个标准 logging.Formatter 具有指定格式字符串的实例。第二个,带身份证 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)
钥匙 '()' 已用作特殊键,因为它不是有效的关键字参数名称,因此不会与调用中使用的关键字参数的名称冲突。这个 '()' 也可以用作相应值是可调用的助记符。
访问外部对象¶
例如,有时配置需要引用配置外部的对象 sys.stderr . 如果配置dict是使用python代码构建的,那么这很简单,但是当通过文本文件(例如json、yaml)提供配置时会出现问题。在文本文件中,没有标准的方法来区分 sys.stderr 从文本字符串 'sys.stderr' . 为了便于区分,配置系统在字符串值中查找特定的特殊前缀,并对它们进行特殊处理。例如,如果文本字符串 'ext://sys.stderr' 在配置中作为值提供,然后 ext:// 将被剥离,剩余的值将使用正常的导入机制进行处理。
这种前缀的处理方式类似于协议处理:有一种通用机制来查找与正则表达式匹配的前缀。 ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$ 据此,如果 prefix 是公认的, suffix 以前缀相关的方式处理,处理结果将替换字符串值。如果不识别前缀,则字符串值将保持原样。
访问内部对象¶
除了外部对象之外,有时还需要在配置中引用对象。这将由配置系统隐式地为它所知道的事情完成。例如,字符串值 'DEBUG' 对于一个 level 在记录器或处理程序中,将自动转换为值 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 会用键决定听写 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' 或者,等价地, '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__() 函数进行导入。您可能希望用您自己的导入机制替换它:如果是这样,您可以替换 importer 的属性 DictConfigurator 或者它的超类 BaseConfigurator 类。但是,您需要小心,因为函数是通过描述符从类中访问的。如果使用可调用的python进行导入,并且希望在类级别而不是实例级别定义它,则需要用 staticmethod() . 例如::
from importlib import import_module
from logging.config import BaseConfigurator
BaseConfigurator.importer = staticmethod(import_module)
你不需要封装 staticmethod() 如果要在配置器上设置可调用的导入 实例 .
配置文件格式¶
配置文件格式 fileConfig() 基于 configparser 功能。文件必须包含名为 [loggers] , [handlers] 和 [formatters] 它按名称标识文件中定义的每种类型的实体。对于每个这样的实体,都有一个单独的部分来标识该实体的配置方式。因此,对于一个名为 log01 在 [loggers] 节,相关配置详细信息保存在节中。 [logger_log01] . 类似地,一个处理程序调用 hand01 在 [handlers] 节的配置将保存在名为 [handler_hand01] ,而格式化程序调用 form01 在 [formatters] 节的配置将在名为 [formatter_form01] . 必须在名为 [logger_root] .
注解
这个 fileConfig() API比 dictConfig() 并且不提供涵盖日志记录某些方面的功能。例如,您不能配置 Filter 对象,用于过滤简单整数级以外的消息,使用 fileConfig() . 如果您需要 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 表示将记录所有消息。级别值为 eval() 在 logging 包的命名空间。
这个 handlers 条目是处理程序名称的逗号分隔列表,必须出现在 [handlers] 部分。这些名称必须出现在 [handlers] 并在配置文件中具有相应的节。
对于根记录器以外的记录器,需要一些附加信息。下面的例子说明了这一点。
[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser
这个 level 和 handlers 条目被解释为根记录器,除非非根记录器的级别被指定为 NOTSET ,系统向更高层次的记录器查询,以确定记录器的有效级别。这个 propagate 条目设置为1表示消息必须传播到此记录器的更高层次结构上的处理程序,或0表示消息 not 传播到层次结构上的处理程序。这个 qualname 条目是记录器的层次通道名称,也就是说应用程序用于获取记录器的名称。
下面举例说明了指定处理程序配置的部分。
[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)
这个 class 条目指示处理程序的类(由 eval() 在 logging 包的命名空间)。这个 level 解释为记录员,以及 NOTSET 意思是“记录一切”。
这个 formatter 条目指示此处理程序的格式化程序的键名。如果为空,则为默认格式设置工具 (logging._defaultFormatter )。如果指定了名称,它必须出现在 [formatters] 并在配置文件中具有相应的节。
这个 args 进入时 eval() 在 logging 包的命名空间是处理程序类的构造函数的参数列表。请参阅相关处理程序的构造函数或下面的示例,以了解如何构造典型条目。如果未提供,则默认为 () .
可选的 kwargs 进入时 eval() 在 logging 包的命名空间是处理程序类的构造函数的关键字参数dict。如果未提供,则默认为 {{}} .
[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
datefmt=
style='%'
validate=True
class=logging.Formatter
格式化程序配置的参数与字典架构中的键相同 formatters section 。
参见
- 模块
logging 日志模块的API引用。
- 模块
logging.handlers 日志模块中包含有用的处理程序。