首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

logging.config

重要

此页面仅包含参考信息。有关教程,请参阅

本节介绍用于配置日志记录模块的API。

1.配置功能

以下功能配置日志记录模块。它们位于logging.config模块中。它们的使用是可选的 - 您可以使用这些函数或通过调用主API(定义在logging自身中)并定义在logging或中声明的处理程序来配置日志记录模块logging.handlers

logging.config.dictConfig(config)

从字典中获取日志配置。该字典的内容在下面的配置字典模式中进行了描述。

如果在配置过程中遇到错误,则此函数将引发具有适当描述性消息的ValueError,TypeError,AttributeError或ImportError。 以下是可能会引发错误的(可能不完整的)条件列表:

  • 不是字符串的字符串,也不是与实际日志记录级别对应的字符串。
  • 传播值不是布尔值。
  • 一个没有相应目的地的ID。
  • 在增量呼叫期间找到不存在的处理程序ID。
  • 无效的记录器名称。
  • 无法解析为内部或外部对象。

解析由DictConfigurator类执行,其构造函数传递用于配置的字典,并且具有configure()方法。 logging.config模块有一个可调参数dictConfigClass,它最初设置为DictConfigurator。 你可以用你自己的合适的实现来替换dictConfigClass的值。

dictConfig()调用dictConfigClass传递指定的字典,然后调用返回对象上的configure()方法使配置生效:

代码语言:javascript
复制
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)

configparser名为fname的-format文件中读取日志配置。文件的格式应如配置文件格式中所述。该功能可以从应用程序中多次调用,允许最终用户从各种预先配置的配置中进行选择(如果开发人员提供了一种机制来呈现选项并加载所选配置)。

参数:

默认值 - 可以在此参数中指定要传递给ConfigParser的默认值。disable_existing_loggers - 如果指定为False,则在进行此调用时存在的记录器保持启用状态。缺省值为True,因为这会以向后兼容的方式启用旧行为。这种行为是为了禁用任何现有的记录器,除非它们或其祖先在记录配置中明确命名。

  • 默认值 - 可以在此参数中指定要传递给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()以启动服务器,并在适当时加入()。 要停止服务器,请调用stopListening()。

要将配置发送到套接字,请读入配置文件,并将其作为一串字节发送到套接字,前面带有一个四字节长度的字符串,该字符串使用二进制打包struct.pack('>L', n)

注意

由于部分配置已通过eval(),因此使用此功能可能会使其用户面临安全风险。虽然该函数仅绑定到一个套接字上localhost,并且不接受来自远程计算机的连接,但有些情况下,不可信的代码可以在调用的进程帐户下运行listen()。具体来说,如果进程调用listen()在多用户机器上运行,而用户不能相互信任,那么恶意用户可以安排在受害用户的进程中运行基本上任意代码,只需连接受害者listen()套接字并发送一个配置,该配置运行攻击者希望在受害者进程中执行的任何代码。如果使用默认端口,这很容易实现,但即使使用不同的端口也不困难)。

logging.config.stopListening()

停止通过呼叫创建的侦听服务器listen()。这通常在调用join()返回值之前调用listen()

2.配置字典架构

描述日志记录配置需要列出要创建的各种对象以及它们之间的连接; 例如,您可以创建一个名为'console'的处理程序,然后说名为'startup'的记录程序将其消息发送到'console'处理程序。 这些对象不限于记录模块提供的那些对象,因为您可能会编写自己的格式化程序或处理程序类。 这些类的参数还可能需要包含外部对象,如sys.stderr。 描述这些对象和连接的语法在下面的对象连接中定义。

2.1 字典模式详细信息

传递给的字典dictConfig()必须包含以下键:

  • 版本 - 被设置为表示模式版本的整数值。目前唯一有效的值是1,但拥有这个键可以使模式发展,同时仍然保持向后兼容性。

所有其他键都是可选的,但如果存在的话,它们将按照下面的描述进行解释。在下面提到'配置字典'的所有情况下,将检查特殊'()'键以查看是否需要自定义实例化。如果是这样,下面用户定义对象中描述的机制用于创建一个实例; 否则,上下文用于确定要实例化的内容。

  • 格式化程序 - 相应的值将是一个字典,其中每个键是一个格式化程序ID,每个值都是一个字典,用于描述如何配置相应的Formatter实例。在配置字典中搜索键格式和datefmt(默认为None),这些用于构造Formatter实例。
  • 过滤器 - 相应的值将是一个字典,其中每个键是一个过滤器ID,每个值是一个字典,描述如何配置相应的过滤器实例。在配置字典中搜索键名(默认为空字符串),这用于构造一个logging.Filter实例。
  • 处理程序 - 相应的值将是一个字典,其中每个键是一个处理程序ID,每个值是一个字典,描述如何配置相应的Handler实例。在配置字典中搜索以下关键字:
代码语言:txt
复制
-  `class` (mandatory). This is the fully qualified name of the handler class.
-  `level` (optional). The level of the handler.
-  `formatter` (optional). The id of the formatter for this handler.
-  `filters` (optional). A list of ids of the filters for this handler.

所有其他 键都作为关键字参数传递给处理程序的构造函数。例如,给出片段:

处理程序:console:class:logging.StreamHandler格式化程序:简短级别:INFO过滤器:allow_foo stream:ext://sys.stdout file:class:logging.handlers.RotatingFileHandler formatter:精确文件名:logconfig.log maxBytes:1024 backupCount:3

带有id控制台的处理程序被实例化为一个logging.StreamHandler,使用sys.stdout作为基础流。 具有id文件的处理程序被实例化为具有关键字参数filename ='logconfig.log',maxBytes = 1024,backupCount = 3的logging.handlers.RotatingFileHandler。

  • 记录器 - 相应的值将是一个字典,其中每个键是一个记录器名称,每个值是一个字典,用于描述如何配置相应的记录器实例。在配置字典中搜索以下关键字:
代码语言:txt
复制
-  `level` (optional). The level of the logger.
-  `propagate` (optional). The propagation setting of the logger.
-  `filters` (optional). A list of ids of the filters for this logger.
-  `handlers` (optional). A list of ids of the handlers for this logger.

指定的记录器将根据指定的级别,传播,过滤器和处理程序进行配置。

  • root- 这将是根记录器的配置。 处理配置将与任何记录器一样,只是传播设置不适用。
  • incremental - 是否将配置解释为现有配置的增量配置。 此值默认为False,这意味着指定的配置会使用现有fileConfig()API使用的相同语义替换现有配置。如果指定的值为True,则按照增量配置一节中所述处理配置。
  • disable_existing_loggers - 是否禁用任何现有的记录器。 该设置镜像fileConfig()中同名的参数。 如果不存在,则此参数默认为True。 如果incremental为True,则该值将被忽略。

2.2 增量配置

为增量配置提供完全的灵活性是很困难的。例如,因为诸如过滤器和格式化程序之类的对象是匿名的,所以一旦设置了配置,在扩充配置时就不可能引用这样的匿名对象。

此外,一旦配置设置完成,就没有一种令人信服的情况,即在运行时任意更改记录器,处理程序,过滤器和格式化程序的对象图; 记录器和处理程序的详细程度可以通过设置级别来控制(并且在记录器的情况下,传播标志)。在多线程环境中,以安全的方式任意更改对象图是有问题的; 虽然并非不可能,但这些好处并不值得它增加实施的复杂性。

因此,当配置字典的增量键存在且为真时,系统将完全忽略任何格式化程序和筛选条目,并仅处理处理程序条目中的级别设置以及记录器和根条目中的级别和传播设置。

在配置dict中使用值可以让配置作为pickle字典通过线路发送到套接字侦听器。因此,长时间运行的应用程序的日志详细程度可以随着时间而改变,而不需要停止并重新启动应用程序。

2.3 对象连接

该模式描述了一组记录对象 - 记录器,处理程序,格式化程序,过滤器 - 它们在对象图中彼此连接。因此,模式需要表示对象之间的连接。例如,说一旦配置完毕,特定的记录器就会附加一个特定的处理程序。为了讨论的目的,我们可以说记录器代表源,而处理器则是两者之间连接的目的地。当然,在配置的对象中,这由记录器持有对处理程序的引用来表示。在配置字典中,这是通过给每个目标对象一个明确标识它的id,然后在源对象的配置中使用id来指示源和目标对象之间存在具有该id的连接来完成的。

因此,例如,请考虑以下YAML代码片段:

代码语言:javascript
复制
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可以是任何字符串值(例如简要的,精确的),它们是暂时的,因为它们只对处理配置字典有用,并用于确定对象之间的连接,并且不会在 配置调用完成。

上面的代码片段表明,名为foo.bar.baz的记录器应该有两个处理程序连接到它,这由处理程序id h1和h2来描述。 h1的格式化程序由id简单描述,而h2的格式化程序由id精确描述。

2.4 用户定义的对象

该模式支持处理程序,过滤器和格式化程序的用户定义对象。(对于不同的实例,记录器不需要具有不同的类型,因此在此配置模式中不支持用户定义的记录器类。)

要配置的对象由详细描述其配置的字典来描述。在某些地方,日志系统将能够从上下文中推断出一个对象是如何实例化的,但是当一个用户定义的对象被实例化时,系统将不知道如何执行此操作。为了为用户定义的对象实例化提供完全的灵活性,用户需要提供一个“工厂” - 一个可调用的对象,它用配置字典调用,并返回实例化的对象。这是通过一个绝对的进入通道来指示工厂在专用钥匙下可用'()'。这里有一个具体的例子:

代码语言:javascript
复制
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简单,是一个具有指定格式字符串的标准logging.Formatter实例。 第二种,默认为id,格式更长,同时也明确定义了时间格式,并且会产生一个用这两个格式字符串初始化的logging.Formatter。 以Python源代码形式显示,简要和默认格式化程序具有配置子词典:

代码语言:javascript
复制
{
  'format' : '%(message)s'
}

以及以下情况:

代码语言:javascript
复制
{
  'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
  'datefmt' : '%Y-%m-%d %H:%M:%S'
}

因为这些字典不包含特殊键'()',所以从上下文推断实例化:因此,logging.Formatter创建了标准实例。第三个格式化器的配置子字典(id custom)为:

代码语言:javascript
复制
{
  '()' : 'my.package.customFormatterFactory',
  'bar' : 'baz',
  'spam' : 99.9,
  'answer' : 42
}

这包含特殊的键'()',这意味着用户定义的实例化是想要的。在这种情况下,将使用指定的工厂可调用函数。如果它是一个实际的可调用对象,它将被直接使用 - 否则,如果指定了一个字符串(如示例中那样),则实际的可调用对象将使用普通导入机制进行定位。将使用配置子字典中的其余项作为关键字参数调用可调用对象。在上面的例子中,带有id的格式化程序custom将被假定为由该调用返回:

代码语言:javascript
复制
my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)

该键'()'已被用作特殊键,因为它不是有效的关键字参数名称,因此不会与调用中使用的关键字参数的名称冲突。这'()'也是一个助记符,相应的值是可调用的。

2.5 访问外部对象

有时候配置需要引用配置外部的对象,例如sys.stderr。 如果使用Python代码构造配置字典,这很简单,但是当通过文本文件(例如JSON,YAML)提供配置时会出现问题。 在一个文本文件中,没有标准的方法来区分sys.stderr和字符串'sys.stderr'。 为了便于区分,配置系统在字符串值中查找某些特殊的前缀并专门处理它们。 例如,如果在配置中提供了字符串'ext://sys.stderr'作为值,那么ext://将被剥离并且使用普通导入机制处理值的其余部分。

这种前缀的处理以类似于协议处理的方式完成:有一种通用机制来查找与正则表达式匹配的前缀^(?P <prefix> [az] +)://(?P <后缀> 。*)$这样,如果前缀被识别,后缀将以前缀相关的方式处理,并且处理结果将替换字符串值。 如果前缀未被识别,则字符串值将保持原样。

2.6 访问内部对象

除了外部对象外,有时还需要引用配置中的对象。 这将由配置系统隐式地完成它所知道的事情。 例如,记录器或处理程序中级别的字符串值“DEBUG”将自动转换为值logging.DEBUG,处理程序,过滤器和格式化程序条目将采用对象标识并解析为相应的目标对象。

但是,日志记录模块未知的用户定义对象需要更通用的机制。 例如,考虑logging.handlers.MemoryHandler,它接受另一个处理程序委托给的目标参数。 由于系统已经知道这个类,所以在配置中,给定的目标只需要是相关目标处理程序的对象ID,系统将从该ID解析为处理程序。 但是,如果用户定义了具有备用处理程序的my.package.MyHandler,则配置系统不会知道该备用程序涉及处理程序。 为了迎合这一点,一个通用的解析系统允许用户指定:

代码语言:javascript
复制
handlers:
  file:
    # configuration of file handler goes here

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

字符串'cfg://handlers.file'将以类似的方式解析为带有ext://前缀的字符串,但查看配置本身而不是导入名称空间。 该机制允许通过点或索引访问,与str.format提供的方式类似。 因此,给出以下片段:

代码语言:javascript
复制
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'会使用键处理程序解析为字典,字符串'cfg://handlers.email将使用处理程序字典中的关键电子邮件解析为字典,等等。 字符串'cfg://handlers.email.toaddrs [1]将解析为'dev_team.domain.tld',字符串'cfg://handlers.email.toaddrs [0]'将解析为值'support_team @使用domain.tld”。 可以使用'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']如果失败。

2.7 导入分辨率和自定义导入程序

默认情况下,导入解析使用内置的__import __()函数进行导入。 您可能需要将其替换为您自己的导入机制:如果是这样,您可以替换DictConfigurator或其超类BaseConfigurator类的importer属性。 但是,由于通过描述符从类访问函数的方式,您需要小心。 如果您使用Python可调用来执行导入,并且想要在类级别而不是实例级别定义它,则需要使用staticmethod()来包装它。 例如:

代码语言:javascript
复制
from importlib import import_module
from logging.config import BaseConfigurator

BaseConfigurator.importer = staticmethod(import_module)

如果您将设置的导入设置为在配置器实例上可调用,则不需要使用staticmethod()进行包装。

3. 配置文件格式

fileConfig()理解的配置文件格式基于configparser功能。 该文件必须包含称为[记录器],[处理程序]和[格式化程序]的部分,它们按名称标识文件中定义的每种类型的实体。 对于每个这样的实体,都有一个单独的部分来标识该实体如何配置。 因此,对于[loggers]部分中名为log01的记录器,相关配置详细信息保存在[logger_log01]部分中。 同样,[handlers]部分中名为hand01的处理程序将其配置保存在名为[handler_hand01]的部分中,而[formatters]部分中名为form01的格式化程序将在名为[formatter_form01]的部分中指定其配置。 根记录器配置必须在名为[logger_root]的部分中指定。

注意

fileConfig()API比dictConfig()API旧,并且不提供覆盖某些日志记录方面的功能。 例如,您无法使用fileConfig()配置Filter对象,该对象提供超出简单整数级别的消息过滤。 如果您需要在日志记录配置中使用Filter实例,则需要使用dictConfig()。 请注意,未来配置功能的增强功能将被添加到dictConfig()中,因此在方便的时候考虑转换到这个更新的API是值得的。

下面给出了文件中这些部分的示例。

代码语言:javascript
复制
[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

根记录器必须指定一个级别和一系列处理程序。根记录器部分的一个例子如下。

代码语言:javascript
复制
[logger_root]
level=NOTSET
handlers=hand01

级别条目可以是DEBUG,INFO,WARNING,ERROR,CRITICAL或NOTSET之一。 仅对于根记录器,NOTSET表示将记录所有消息。 级别值是eval()在日志包名称空间的上下文中使用的。

处理程序条目是逗号分隔的处理程序名称列表,它必须出现在[处理程序]部分。 这些名称必须出现在[handlers]部分,并且在配置文件中有相应的部分。

对于根记录器以外的记录器,需要一些附加信息。以下示例说明了这一点。

代码语言:javascript
复制
[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser

级别和处理程序条目解释为根记录器,除非如果非根记录器的级别被指定为NOTSET,则系统会在层次结构的更高层次上咨询记录器以确定记录器的有效级别。 传播条目设置为1以指示消息必须传播到记录器层次结构中来自此记录器的处理程序,或者0表示消息不传播到层次结构中的处理程序。 质量名输入是记录器的分层通道名称,也就是应用程序用来获取记录器的名称。

指定处理程序配置的部分由以下示例。

代码语言:javascript
复制
[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)

类条目指示处理程序的类(由记录包的名称空间中的eval()确定)。 级别被解释为记录器,而NOTSET被认为是“记录所有”。

在版本2.6中进行了更改:增加了对处理程序类的解决方案,作为虚线模块和类名称。

格式化程序条目指示该处理程序的格式化程序的键名称。 如果为空,则使用默认格式化程序(logging._defaultFormatter)。 如果指定了名称,它必须出现在[formatters]部分,并在配置文件中有相应的部分。

当eval()在日志包名称空间的上下文中时,args条目是处理程序类构造函数的参数列表。 请参阅相关处理程序的构造函数或下面的示例,查看典型条目的构造方式。

代码语言:javascript
复制
[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')

指定格式化程序配置的部分如下所示。

代码语言:javascript
复制
[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s
datefmt=
class=logging.Formatter

格式条目是整体格式字符串,datefmt条目是strftime()兼容的日期/时间格式字符串。 如果为空,则该包将替换ISO8601格式的日期/时间,这几乎等同于指定日期格式字符串'%Y-%m-%d%H:%M:%S'。 ISO8601格式还指定了使用上述格式字符串附加在逗号分隔符后的毫秒数。 ISO8601格式的示例时间是2003-01-23 00:29:50,411。

类条目是可选的。 它表示格式化程序类的名称(作为虚线模块和类名称)。此选项对实例化Formatter子类很有用。 Formatter的子类可以以扩展或压缩格式显示异常追溯。

注意

由于如上所述使用了eval(),因此使用listen()通过套接字发送和接收配置会导致潜在的安全风险。 风险限于多个不具有相互信任的用户在同一台机器上运行代码的情况; 请参阅listen()文档以获取更多信息。

扩展内容

Module logging 记录模块的API参考。 Module logging.handlers 记录模块附带的有用处理程序。

扫码关注腾讯云开发者

领取腾讯云代金券