15.8. logging.config —日志记录配置

Important

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

源代码: Lib/logging/config.py


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

15.8.1. 配置Function

以下Function配置日志记录模块。它们位于logging.config模块中。它们的使用是可选的-您可以使用这些Function或pass调用主 API(在logging本身中定义)并定义在logginglogging.handlers中语句的处理程序来配置日志记录模块。

logging.config. dictConfig(* config *)

Note

从字典中获取日志记录配置。该字典的内容在下面的配置字典架构中描述。

如果在配置过程中遇到错误,此Function将使用适当的描述性消息引发ValueErrorTypeErrorAttributeErrorImportError。以下是(可能不完整)会引起错误的条件列表:

  • level不是字符串,也不是与实际日志记录级别不对应的字符串。

  • propagate值,不是布尔值。

  • 没有对应目的地的 ID。

  • 在增量调用期间发现不存在的处理程序 ID。

  • 无效的 Logger 名称。

  • 无法解析为内部或外部对象。

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

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

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

例如,DictConfigurator的子类可以在其自己的init()中调用DictConfigurator.__init__(),然后设置自定义前缀,这些前缀可在后续的configure()调用中使用。 dictConfigClass将绑定到这个新的子类,然后可以完全按照默认的非自定义状态调用dictConfig()

2.7 版的新Function。

  • logging.config. fileConfig(* fname defaults = None disable_existing_loggers = True *)

    • 从名为* fname *的configparser格式文件中读取日志配置。文件格式应为配置文件格式中所述。可以从应用程序中多次调用此Function,从而使finally用户可以从各种预先设置的配置中进行选择(如果开发人员提供了一种机制来呈现选择并加载所选的配置)。
  • Parameters

      • defaults –可以在此参数中指定要传递给 ConfigParser 的默认值。
  • disable_existing_loggers –如果指定为False,则启用此调用时存在的 Logger。默认值为True,因为它以向后兼容的方式启用了旧的行为。此行为是要禁用所有现有 Logger,除非它们或它们的祖先在记录配置中被明确命名。

在 2.6 版中进行了更改:添加了disable_existing_loggers关键字参数。以前,现有的 Logger 总是被禁用。

  • logging.config. listen(* port = DEFAULT_LOGGING_CONFIG_PORT *)
    • 在指定端口上启动套接字服务器,并侦听新配置。如果未指定端口,则使用模块的默认DEFAULT_LOGGING_CONFIG_PORT。日志配置将作为适合fileConfig()处理的文件发送。返回一个Thread实例,您可以在该实例上调用start()来启动服务器,并且可以在适当的情况下join()。要停止服务器,请调用stopListening()

要将配置发送到套接字,请读入配置文件,然后以字节串的形式将其发送到套接字,然后以struct.pack('>L', n)的形式将四字节长度的字符串打包成二进制。

Note

由于部分配置是passeval()传递的,因此使用此Function可能会使其用户面临安全风险。虽然该函数仅绑定到localhost上的套接字,因此不接受来自远程计算机的连接,但是在某些情况下,可以在调用listen()的进程的情况下运行不受信任的代码。具体来说,如果调用listen()的进程在用户无法互相信任的多用户计算机上运行,则恶意用户可以安排在受害者用户的进程中运行基本上任意的代码,只需连接到受害者的listen()套接字并发送配置即可它运行攻击者希望在受害者进程中执行的任何代码。如果使用默认端口,这样做特别容易,但是即使使用其他端口也不难。

  • logging.config. stopListening ( )
    • 停止pass调用listen()创建的监听服务器。通常在从listen()返回的值上调用join()之前调用此方法。

15.8.2. 配置字典架构

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

15.8.2.1. 词典架构详细信息

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

    • version *-设置为代表架构版本的整数值。当前唯一的有效值为 1,但是拥有此密钥可以使架构 Developing,同时仍然保持向后兼容性。

所有其他键都是可选的,但是如果存在,它们将按以下说明进行解释。在下面提到“配置命令”的所有情况下,都将检查它的特殊'()'键以查看是否需要自定义实例。如果是这样,则以下User-defined objects中描述的机制用于创建实例;否则,上下文用于确定实例化什么。

    • formatters *-相应的值将是一个字典,其中每个键是一个格式化程序 ID,每个值是一个描述如何配置相应的Formatter实例的字典。

在配置字典中搜索键formatdatefmt(默认值为None),并将它们用于构建Formatter实例。

    • filters *-相应的值将是一个字典,其中每个键是一个过滤器 ID,每个值是一个描述如何配置相应的 Filter 实例的字典。

在配置字典中搜索键name(默认为空字符串),该键用于构造logging.Filter实例。

    • handlers *-相应的值将是一个 dict,其中每个键是一个处理程序 id,每个值是一个 dict,用于描述如何配置相应的 Handler 实例。

在配置字典中搜索以下键:

  • 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的处理程序将以sys.stdout作为基础流实例化为logging.StreamHandler。 ID 为file的处理程序使用关键字参数filename='logconfig.log', maxBytes=1024, backupCount=3实例化为logging.handlers.RotatingFileHandler

    • loggers *-相应的值将是一个字典,其中每个键是一个 Logger 名称,每个值是一个描述如何配置相应 Logger 实例的字典。

在配置字典中搜索以下键:

  • level(可选)。Logger 的级别。

    • propagate(可选)。Logger 的传播设置。

    • filters(可选)。此 Logger 的过滤器 ID 的列表。

    • handlers(可选)。此 Logger 的处理程序的 ID 列表。

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

    • root *-这将是 rootLogger 的配置。除propagate设置不适用外,配置处理将与所有 Logger 相同。
    • incremental *-是否将配置解释为现有配置的增量。该值默认为False,这意味着指定的配置将使用与现有fileConfig() API 相同的语义替换现有配置。

如果指定的值为True,则按照Incremental Configuration一节中的描述处理配置。

    • disable_existing_loggers -是否要禁用任何现有的 Logger。此设置镜像fileConfig()中具有相同名称的参数。如果不存在,则此参数默认为True。如果 incremental *为True,则忽略此值。

15.8.2.2. 增量配置

很难为增量配置提供完全的灵 Active。例如,因为诸如过滤器和格式化程序之类的对象是匿名的,所以一旦构建了配置,就无法在扩充配置时引用此类匿名对象。

此外,一旦配置成功,就没有必要在运行时随意更改 Logger,处理程序,过滤器,格式化程序的对象图;Logger 和处理程序的详细程度可以仅pass设置级别来控制(对于 Logger,还可以设置传播标志)。在多线程环境中,以安全的方式任意更改对象图是有问题的。尽管并非没有可能,但这样做的好处并不值得其增加实施的复杂性。

因此,当配置字典的incremental键存在且为True时,系统将完全忽略任何formattersfilters条目,并且仅处理handlers条目中的level设置以及loggersroot条目中的levelpropagate设置。 。

在配置字典中使用一个值可以使配置作为腌渍字典pass网络发送到套接字侦听器。因此,长时间运行的应用程序的日志记录详细程度可以随着时间而改变,而无需停止和重新启动应用程序。

15.8.2.3. 对象连接

该模式描述了一组记录对象-Logger,处理程序,格式化程序,过滤器-它们在对象图中相互连接。因此,该模式需要表示对象之间的连接。例如,假设配置后,特定的 Logger 便已附加了特定的处理程序。出于讨论的目的,我们可以说 Logger 代表两者之间连接的源,而处理程序代表两者的连接。当然,在已配置的对象中,这由 Logger 代表对处理程序的引用来表示。在配置命令中,这是pass给每个目标对象一个明确标识它的 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 源代码格式更具可读性.)

Logger 的 ID 是 Logger 名称,将以编程方式使用它们来获取对这些 Logger 的引用,例如foo.bar.baz。格式化程序和过滤器的 ID 可以是任何字符串值(例如上面的briefprecise),并且它们是瞬态的,因为它们仅对处理配置字典有意义,并用于确定对象之间的连接,并且当配置调用完成。

上面的代码片段指示名为foo.bar.baz的 Logger 应附加两个处理程序,这些处理程序由处理程序 ID h1h2进行描述。 h1的格式化程序由 id brief描述,h2的格式化程序由 id precise描述。

15.8.2.4. 用户定义的对象

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

用字典描述要配置的对象,并详细说明它们的配置。在某些地方,日志记录系统将能够从上下文中推断出如何实例化对象,但是当要实例化用户定义的对象时,系统将不知道如何执行此操作。为了为用户定义的对象实例化提供完全的灵 Active,用户需要提供一个“工厂”(可调用对象),该对象可pass配置字典进行调用并返回实例化的对象。这是pass在特殊键'()'下提供了到工厂的绝对导入路径来表示的。这是一个具体的例子:

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 源代码形式显示的briefdefault格式化程序具有配置子词典:

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

and:

{
  '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
}

其中包含特殊键'()',这意味着需要用户定义的实例化。在这种情况下,将使用指定的工厂可调用对象。如果它是一个实际的可调用对象,则将直接使用它-否则,如果您指定一个字符串(如示例中所示),则将使用常规的导入机制来定位该实际的可调用对象。将使用配置子词典中的 remaining 项目作为关键字参数来调用可调用对象。在上面的示例中,将假定 ID custom的格式化程序是pass调用返回的:

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

'()'已用作特殊键,因为它不是有效的关键字参数名称,因此不会与调用中使用的关键字参数名称冲突。 '()'还充当助记符,表示相应的值是可调用的。

15.8.2.5. 访问外部对象

有时,某个配置需要引用该配置外部的对象,例如sys.stderr。如果使用 python 代码构造配置字典,这很简单,但是当pass文本文件(例如 JSON,YAML)提供配置时会出现问题。在文本文件中,没有标准的方法可以将sys.stderr与 Literals 字符串'sys.stderr'区分开。为了促进这种区分,配置系统会在字符串值中查找某些特殊前缀,并对其进行特殊处理。例如,如果在配置中将 Literals 字符串'ext://sys.stderr'作为值提供,则将剥离ext://并使用常规导入机制处理该值的其余部分。

此类前缀的处理方式类似于协议处理:存在一种通用机制来查找与正则表达式^(?P<prefix>[a-z]+)://(?P<suffix>.*)$匹配的前缀,从而,如果识别出prefix,则以前缀相关的方式处理suffix,处理结果替换字符串值。如果未识别前缀,则字符串值将保持不变。

15.8.2.6. 访问内部对象

除外部对象外,有时还需要引用配置中的对象。配置系统将针对它所了解的内容隐式完成此操作。例如,Logger 或处理程序中level的字符串值'DEBUG'将自动转换为值logging.DEBUG,并且handlersfiltersformatter条目将获取对象 ID 并解析为适当的目标对象。

但是,对于logging模块未知的用户定义对象,需要一种更通用的机制。例如,考虑logging.handlers.MemoryHandler,它接受target参数,这是另一个要委托给的处理程序。由于系统已经知道此类,因此在配置中,给定的target仅是相关目标处理程序的对象 ID,系统将从该 ID 解析为处理程序。但是,如果用户定义了具有alternate处理程序的my.package.MyHandler,则配置系统将不知道alternate引用了处理程序。为此,通用解析系统允许用户指定:

handlers:
  file:
    # configuration of file handler goes here

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

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

handlers:
  email:
    class: logging.handlers.SMTPHandler
    mailhost: localhost
    fromaddr: [email protected]
    toaddrs:
      - [email protected]
      - [email protected]
    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]'将解析为值'[email protected]'。可以使用'cfg://handlers.email.subject'或等效地'cfg://handlers.email[subject]'来访问subject值。仅当键包含空格或非字母数字字符时,才需要使用后一种形式。如果索引值仅由十进制数字组成,则将try使用相应的整数值进行访问,如果需要,则返回到字符串值。

给定字符串cfg://handlers.myhandler.mykey.123,它将解析为config_dict['handlers']['myhandler']['mykey']['123']。如果将字符串指定为cfg://handlers.myhandler.mykey[123],则系统将try从config_dict['handlers']['myhandler']['mykey'][123]检索值,如果失败则回退到config_dict['handlers']['myhandler']['mykey']['123']

15.8.2.7. 导入分辨率和自定义 import 商

默认情况下,导入分辨率使用内置的import()函数进行导入。您可能希望用自己的导入机制替换它:如果是这样,则可以替换DictConfiguratorimporter属性或其超类BaseConfigurator类。但是,由于需要pass Descriptors 从类访问函数的方式,因此需要小心。如果您使用可调用的 Python 进行导入,并且想要在类级别而不是实例级别定义它,则需要使用staticmethod()进行包装。例如:

from importlib import import_module
from logging.config import BaseConfigurator

BaseConfigurator.importer = staticmethod(import_module)

如果要在配置程序* instance *上设置可调用的 import,则无需使用staticmethod()换行。

15.8.3. 配置文件格式

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

Note

fileConfig() API 比dictConfig() API 旧,并且不提供覆盖日志记录某些方面的Function。例如,您不能配置Filter对象,该对象使用fileConfig()过滤超出简单整数级别的消息。如果需要在日志记录配置中包含Filter的实例,则需要使用dictConfig()。请注意,将来对配置Function的增强将添加到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 必须指定级别和处理程序列表。以下是根 Logger 部分的示例。

[logger_root]
level=NOTSET
handlers=hand01

level条目可以是DEBUG, INFO, WARNING, ERROR, CRITICALNOTSET之一。仅对于根 Logger,NOTSET表示将记录所有消息。在logging包的名称空间的上下文中对级别值eval()求值。

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

对于除根 Logger 以外的其他 Logger,还需要一些其他信息。下面的示例对此进行了说明。

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

levelhandlers条目的解释方式与根 Logger 相同,不同的是,如果将非根 Logger 的级别指定为NOTSET,则系统将咨询层次结构中更高级别的 Logger,以确定 Logger 的有效级别。 propagate条目设置为 1 表示消息必须从此 Logger 传播到更高级别的处理程序,或设置为 0 表示消息“不”传播到该层次结构的处理程序。 qualname条目是 Logger 的分层通道名称,即应用程序用来获取 Logger 的名称。

指定处理程序配置的部分如下所示。

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

class条目指示处理程序的类(由logging包的命名空间中的eval()确定)。 level被解释为 Logger,而NOTSET被认为是“记录所有内容”。

在 2.6 版中进行了更改:添加了对将处理程序的类解析为点分模块和类名的支持。

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

logging包的命名空间的上下文中eval()时,args条目是处理程序类的构造函数的参数列表。请参阅相关处理程序的构造函数,或参考以下示例,以了解如何构造典型条目。

[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的子类可以扩展或压缩格式显示异常回溯。

Note

由于如上所述使用eval(),使用listen()pass套接字发送和接收配置会导致潜在的安全风险。风险仅限于没有相互信任的多个用户在同一台计算机上运行代码的情况;有关更多信息,请参见listen()文档。

See also

  • Module logging

  • 日志记录模块的 API 参考。

  • Module logging.handlers

  • 日志记录模块随附的有用处理程序。