Skip to main content

16.6. logging — Python的日志记录工具

源代码: Lib/logging/__init__.py


该模块定义了为应用程序和库实现灵活的事件记录系统的函数和类。

使用标准库模块提供的日志API的主要好处是所有Python模块都可以参与日志记录,因此您的应用程序日志可以包含与来自第三方模块的消息集成的自己的消息。

该模块提供了大量的功能和灵活性。如果你不熟悉日志记录,最好的办法就是看看教程(见右边的链接)。

模块定义的基本类及其功能如下所示。

  • 记录器暴露应用程序代码直接使用的接口。

  • 处理程序将日志记录(由记录器创建)发送到适当的目标。

  • 过滤器提供了一种更细粒度的功能,用于确定要输出哪些日志记录。

  • 格式化程序指定最终输出中的日志记录的布局。

16.6.1. 记录器对象

记录器具有以下属性和方法。注意,记录器从不直接实例化,而是总是通过模块级函数 logging.getLogger(name)。对具有相同名称的 getLogger() 的多次调用将始终返回对同一Logger对象的引用。

name 可能是一个以句点分隔的分层值,如 foo.bar.baz (尽管它也可以只是简单的 foo)。在分层列表中进一步向下的记录器是列表中较高的记录器的子节点。例如,给定具有 foo 名称的记录器,名称为 foo.barfoo.bar.bazfoo.bam 的记录器都是 foo 的后代。记录器名称层次结构类似于Python包层次结构,如果您使用推荐的结构 logging.getLogger(__name__) 在每个模块的基础上组织记录器,则它与Python包层次结构相同。这是因为在模块中,__name__ 是Python包命名空间中的模块名称。

class logging.Logger
Logger.propagate

如果这个计算结果为真,记录到这个记录器的事件将被传递给高级(祖先)记录器的处理器,以及连接到这个记录器的任何处理器。消息直接传递到祖先记录器的处理程序 - 不考虑所讨论的祖先记录器的级别和过滤器。

如果此计算结果为false,则日志消息不会传递到祖先记录器的处理程序。

构造函数将此属性设置为 True

注解

如果将一个处理程序附加到记录器 and 的一个或多个祖先,它可能会多次发出相同的记录。通常,您不需要将处理程序附加到多个记录器 - 如果您只是将其附加到记录器层次结构中最高的适当记录器,则它将看到所有后代记录器记录的所有事件,前提是它们的传播设置被设置为 True。一个常见的情况是将处理程序仅附加到根记录器,并让传播处理其余的。

Logger.setLevel(lvl)

将此记录器的阈值设置为 lvl。记录比 lvl 严重的消息将被忽略。当创建日志记录器时,级别设置为 NOTSET (当记录器是根记录器时,这将导致处理所有消息,或者当记录器是非根记录器时,它将委派给父节点)。注意,根记录器是用级别 WARNING 创建的。

术语“委派给父”意味着如果记录器具有级别NOTSET,则遍历其祖先记录器链,直到找到具有除了NOTSET之外的级别的祖先,或者达到根。

如果找到具有除了NOTSET之外的级别的祖先,则该祖先的级别被视为祖先搜索开始的记录器的有效级别,并且用于确定如何处理日志记录事件。

如果到达根,并且它具有NOTSET级别,则将处理所有消息。否则,根的级别将用作有效级别。

有关级别列表,请参阅 日志级别

在 3.2 版更改: lvl 参数现在接受级别的字符串表示,例如“INFO”,作为整数常量(如 INFO)的替代。然而,注意,级别在内部存储为整数,并且方法例如 getEffectiveLevel()isEnabledFor() 将返回/期望被传递的整数。

Logger.isEnabledFor(lvl)

指示此记录器是否会处理严重性 lvl 的消息。此方法首先检查由 logging.disable(lvl) 设置的模块级别级别,然后检查由 getEffectiveLevel() 确定的记录器的有效级别。

Logger.getEffectiveLevel()

表示此记录仪的有效级别。如果已使用 setLevel() 设置了除 NOTSET 之外的值,则返回该值。否则,将向根向前遍历层次结构,直到找到除 NOTSET 之外的值,并返回该值。返回的值是一个整数,通常是 logging.DEBUGlogging.INFO 等之一。

Logger.getChild(suffix)

返回一个记录器,它是此记录器的后代,由后缀确定。因此,logging.getLogger('abc').getChild('def.ghi') 将返回与 logging.getLogger('abc.def.ghi') 返回的相同的记录器。这是一个方便的方法,当父记录器使用例如 __name__ 而不是文字字符串。

3.2 新版功能.

Logger.debug(msg, *args, **kwargs)

在此记录器上记录具有级别 DEBUG 的消息。 msg 是消息格式字符串,args 是使用字符串格式化运算符合并到 msg 中的参数。 (请注意,这意味着您可以使用格式字符串中的关键字以及单个字典参数。)

kwargs 中有三个被检查的关键字参数:exc_infostack_infoextra

如果 exc_info 未评估为false,则会导致将异常信息添加到日志记录消息中。如果提供了异常元组(以 sys.exc_info() 返回的格式)或异常实例,则使用它;否则,调用 sys.exc_info() 来获取异常信息。

第二个可选的关键字参数是 stack_info,默认为 False。如果为true,则将堆栈信息添加到日志记录消息中,包括实际的日志调用。注意,这不是与通过指定 exc_info 显示的堆栈信息相同的堆栈信息:前者是从堆栈底部到当前线程中的日志记录调用的堆栈帧,而后者是关于已解绕的堆栈帧的信息,跟随异常,同时搜索异常处理程序。

您可以独立于 exc_info 指定 stack_info,例如只是展示你如何到达代码中的某一点,即使没有引发异常。堆栈帧在标题行后面打印:

Stack (most recent call last):

这模仿显示异常框架时使用的 Traceback (most recent call last):

第三个关键字参数是 extra,可用于传递一个字典,用于填充为具有用户定义属性的日志记录事件创建的LogRecord的__dict__。然后可以根据需要使用这些自定义属性。例如,它们可以合并到记录的消息中。例如:

FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logger = logging.getLogger('tcpserver')
logger.warning('Protocol problem: %s', 'connection reset', extra=d)

将打印类似的东西

2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset

extra 中传递的字典中的键不应与日志记录系统使用的键冲突。 (有关日志记录系统使用哪些键的更多信息,请参阅 Formatter 文档。)

如果您选择在记录的消息中使用这些属性,您需要小心谨慎。在上面的例子中,例如,Formatter 已经被设置有期望在LogRecord的属性字典中的“clientip”和“user”的格式字符串。如果缺少这些,则不会记录消息,因为会发生字符串格式化异常。所以在这种情况下,你总是需要通过这些键的 extra 字典。

虽然这可能很讨厌,但是此功能旨在用于特殊情况,例如多线程服务器,其中相同的代码在许多上下文中执行,并且出现的有趣条件取决于该上下文(例如远程客户端IP地址和已认证用户名,在上面的示例中)。在这种情况下,可能特定的 Formatter 将与特定的 Handler 一起使用。

3.2 新版功能: 添加了 stack_info 参数。

在 3.5 版更改: exc_info 参数现在可以接受异常实例。

Logger.info(msg, *args, **kwargs)

在此记录器上记录具有级别 INFO 的消息。参数被解释为 debug()

Logger.warning(msg, *args, **kwargs)

在此记录器上记录具有级别 WARNING 的消息。参数被解释为 debug()

注解

存在过时的方法 warn,其功能上与 warning 相同。由于 warn 已弃用,请不要使用 - 使用 warning

Logger.error(msg, *args, **kwargs)

在此记录器上记录具有级别 ERROR 的消息。参数被解释为 debug()

Logger.critical(msg, *args, **kwargs)

在此记录器上记录具有级别 CRITICAL 的消息。参数被解释为 debug()

Logger.log(lvl, msg, *args, **kwargs)

在此记录器上记录具有整数级别 lvl 的消息。其他参数被解释为 debug()

Logger.exception(msg, *args, **kwargs)

在此记录器上记录具有级别 ERROR 的消息。参数被解释为 debug()。异常信息被添加到日志消息中。这个方法只能从异常处理程序中调用。

Logger.addFilter(filt)

将指定的过滤器 filt 添加到此记录器。

Logger.removeFilter(filt)

从此记录器中删除指定的过滤器 filt

Logger.filter(record)

将此记录器的过滤器应用于记录,并在要处理记录时返回true值。依次查询过滤器,直到其中一个返回假值。如果它们都不返回false值,则将处理记录(传递给处理程序)。如果一个返回false值,则不会对记录进行进一步处理。

Logger.addHandler(hdlr)

将指定的处理程序 hdlr 添加到此记录器。

Logger.removeHandler(hdlr)

从此记录器中删除指定的处理程序 hdlr

Logger.findCaller(stack_info=False)

查找调用者的源文件名和行号。将文件名,行号,函数名和堆栈信息作为4元素元组返回。除非 stack_infoTrue,否则堆栈信息将作为 None 返回。

Logger.handle(record)

通过将记录传递给与此记录器及其祖先相关联的所有处理程序(直到找到 propagate 的false值),即可处理记录。此方法用于从套接字接收的未压缩记录,以及本地创建的记录。记录器级过滤使用 filter() 应用。

Logger.makeRecord(name, lvl, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None)

这是一个工厂方法,可以在子类中重写以创建专用 LogRecord 实例。

Logger.hasHandlers()

检查此记录器是否已配置任何处理程序。这是通过在记录器层次结构中查找此记录器及其父节点中的处理程序来完成的。如果找到处理程序,则返回 True,否则返回 False。当找到具有“propagate”属性设置为false的记录器时,该方法停止搜索层次结构 - 这将是检查处理程序是否存在的最后一个记录器。

3.2 新版功能.

16.6.2. 日志级别

记录级别的数值在下表中给出。如果要定义自己的级别,并需要它们具有相对于预定义级别的特定值,这些主要是感兴趣的。如果定义具有相同数值的级别,它将覆盖预定义的值;预定义名称将丢失。

水平

数值

CRITICAL

50

ERROR

40

WARNING

30

INFO

20

DEBUG

10

NOTSET

0

16.6.3. 处理程序对象

处理程序具有以下属性和方法。注意,Handler 从不直接实例化;这个类充当更有用的子类的基础。然而,子类中的 __init__() 方法需要调用 Handler.__init__()

Handler.__init__(level=NOTSET)

通过设置 Handler 实例的级别,将过滤器列表设置为空列表并创建锁(使用 createLock())来对I/O机制进行序列化访问来初始化 Handler 实例。

Handler.createLock()

初始化线程锁,可以用于序列化对可能不是线程安全的底层I/O功能的访问。

Handler.acquire()

获取使用 createLock() 创建的线程锁。

Handler.release()

释放通过 acquire() 获取的线程锁。

Handler.setLevel(lvl)

将此处理程序的阈值设置为 lvl。记录比 lvl 严重的消息将被忽略。创建处理程序时,级别设置为 NOTSET (这将导致处理所有消息)。

有关级别列表,请参阅 日志级别

在 3.2 版更改: lvl 参数现在接受级别的字符串表示,例如“INFO”,作为整数常量(如 INFO)的替代。

Handler.setFormatter(form)

将此处理程序的 Formatter 设置为 form

Handler.addFilter(filt)

将指定的过滤器 filt 添加到此处理程序。

Handler.removeFilter(filt)

从此处理程序中删除指定的过滤器 filt

Handler.filter(record)

将此处理程序的过滤器应用于记录,并在要处理记录时返回true值。依次查询过滤器,直到其中一个返回假值。如果没有一个返回false值,则将发出记录。如果一个返回一个false值,处理程序将不会发出记录。

Handler.flush()

确保所有日志记录输出已刷新。此版本不做任何事情,并且旨在由子类实现。

Handler.close()

整理处理程序使用的任何资源。此版本没有输出,但从处理程序的内部列表中删除处理程序,当 shutdown() 被调用时,该处理程序被关闭。子类应该确保从重写的 close() 方法中调用。

Handler.handle(record)

根据可能已添加到处理程序的过滤器,有条件地发出指定的日志记录。使用I/O线程锁的获取/释放来包裹记录的实际发射。

Handler.handleError(record)

当在 emit() 调用期间遇到异常时,应该从处理程序中调用此方法。如果模块级属性 raiseExceptionsFalse,则会忽略异常。这是日志系统最需要的 - 大多数用户不会关心日志系统中的错误,他们对应用程序错误更感兴趣。但是,如果您愿意,您可以将其替换为自定义处理程序。指定的记录是在异常发生时正在处理的记录。 (raiseExceptions 的默认值是 True,因为这在开发期间更有用)。

Handler.format(record)

对记录进行格式化 - 如果设置了格式化程序,请使用它。否则,请为模块使用默认格式化程序。

Handler.emit(record)

执行实际记录指定日志记录所需的任何操作。此版本旨在通过子类实现,因此提出了 NotImplementedError

有关作为标准包括的处理程序的列表,请参阅 logging.handlers

16.6.4. 格式化对象

Formatter 对象具有以下属性和方法。它们负责将 LogRecord 转换为(通常)可以由人或外部系统解释的字符串。基本 Formatter 允许指定格式化字符串。如果没有提供,则使用默认值 '%(message)s',其仅包括记录调用中的消息。要在格式化的输出中有其他信息项(如时间戳),请继续阅读。

格式化器可以使用格式字符串来初始化,该格式字符串利用 LogRecord 属性的知识 - 例如上面提到的默认值利用用户的消息和参数被预格式化为 LogRecordmessage 属性的事实。此格式字符串包含标准的Python%样式映射键。有关字符串格式化的更多信息,请参见第 printf 样式字符串格式 节。

LogRecord 中有用的映射键在 LogRecord属性 部分中给出。

class logging.Formatter(fmt=None, datefmt=None, style='%')

返回 Formatter 类的新实例。实例使用消息的整个格式字符串以及消息的日期/时间部分的格式字符串进行初始化。如果没有指定 fmt,则使用 '%(message)s'。如果未指定 datefmt,则使用ISO8601日期格式。

style 参数可以是’%’,’{‘或’$’之一,并确定如何将格式字符串与其数据合并:使用%格式化,str.format()string.Template 之一。有关使用{ - 和$格式化日志消息的更多信息,请参阅 在应用程序中使用特定的格式化样式

在 3.2 版更改: 添加了 style 参数。

format(record)

记录的属性字典用作字符串格式化操作的操作数。返回结果字符串。在格式化字典之前,执行几个准备步骤。使用 msg%args 计算记录的 message 属性。如果格式化字符串包含 '(asctime)',则调用 formatTime() 来设置事件时间的格式。如果有异常信息,它使用 formatException() 格式化并附加到消息。注意,格式化的异常信息被缓存在属性 exc_text 中。这是非常有用的,因为异常信息可以通过线路进行挑选和发送,但是如果您有多个 Formatter 子类自定义异常信息的格式,您应该小心。在这种情况下,您必须在格式化程序完成格式化后清除缓存的值,以便下一个处理事件的格式化程序不使用缓存的值,而是重新重新计算。

如果堆栈信息可用,它将附加在异常信息之后,如果需要,使用 formatStack() 进行转换。

formatTime(record, datefmt=None)

这个方法应该由 format() 通过格式化程序调用,该格式化程序想要使用格式化的时间。此方法可以在格式化程序中覆盖以提供任何特定要求,但基本行为如下:如果指定 datefmt (字符串),则与 time.strftime() 一起使用格式化记录的创建时间。否则,使用ISO8601格式。返回生成的字符串。

此函数使用用户可配置的函数将创建时间转换为元组。缺省情况下,使用 time.localtime()。要为特定格式化程序实例更改此属性,请将 converter 属性设置为具有与 time.localtime()time.gmtime() 相同签名的函数。要为所有格式化程序更改它,例如,如果您希望所有日志记录时间以GMT显示,请在 Formatter 类中设置 converter 属性。

在 3.3 版更改: 以前,默认ISO 8601格式是硬编码的,如下例所示:2010-09-06 22:38:15,292,其中逗号之前的部分由strptime格式字符串('%Y-%m-%d %H:%M:%S')处理,逗号后面的部分为毫秒值。因为strptime没有毫秒的格式占位符,所以使用另一个格式字符串 '%s,%03d' —附加毫秒值,并且这两个格式字符串都已硬编码到此方法中。随着更改,这些字符串被定义为类级属性,可以在实例级别覆盖,如果需要。属性的名称是 default_time_format (用于strptime格式字符串)和 default_msec_format (用于附加毫秒值)。

formatException(exc_info)

将指定的异常信息(由 sys.exc_info() 返回的标准异常元组)作为字符串格式化。这个默认实现只使用 traceback.print_exception()。返回生成的字符串。

formatStack(stack_info)

将指定的堆栈信息(由 traceback.print_stack() 返回的字符串,但删除最后一个换行符)格式化为字符串。这个默认实现只返回输入值。

16.6.5. 过滤器对象

Filters 可以被 HandlersLoggers 用于比级别提供的更复杂的过滤。基本过滤器类仅允许低于记录器层次结构中某个点的事件。例如,用“AB”初始化的过滤器将允许由记录器“A.B”,“ABC”,“ABCD”,“ABD”等记录的事件,而不是“A.BB”,“BAB”等。如果使用空字符串初始化,则传递所有事件。

class logging.Filter(name='')

返回 Filter 类的实例。如果指定 name,它将命名一个记录器,它与其子节点一起将允许其事件通过过滤器。如果 name 是空字符串,则允许每个事件。

filter(record)

是否记录指定的记录?对于no,返回0,对于yes,返回非零。如果认为适当,可以通过该方法就地修改记录。

注意,在处理程序发出事件之前,请参考处理程序附带的过滤器,而在将事件发送到处理程序之前,在记录事件(使用 debug()info() 等)时会查询附加到记录程序的过滤器。这意味着,由后代记录器生成的事件不会被记录器的过滤器设置过滤,除非过滤器也应用于这些后代记录器。

你实际上不需要子类化 Filter:你可以传递任何具有相同语义的 filter 方法的实例。

在 3.2 版更改: 您不需要创建专门的 Filter 类,或使用其他类与 filter 方法:您可以使用函数(或其他可调用)作为过滤器。过滤逻辑将检查过滤器对象是否具有 filter 属性:如果是,则假定它是一个 Filter,并调用其 filter() 方法。否则,假定它是一个可调用的,并以该记录作为单个参数进行调用。返回的值应符合 filter() 返回的值。

尽管过滤器主要用于基于比级别更复杂的标准过滤记录,但它们可以查看由其附加到的处理程序或记录器处理的每个记录:如果您想要执行某些操作,记录由特定记录器或处理程序处理,或者在正在处理的LogRecord中添加,更改或删除属性。显然,更改LogRecord需要小心,但它允许将上下文信息注入日志(请参阅 使用过滤器来传递上下文信息)。

16.6.6. LogRecord对象

LogRecord 实例由 Logger 每次记录时自动创建,并且可以通过 makeLogRecord() 手动创建(例如,从通过线路接收的腌制事件)。

class logging.LogRecord(name, level, pathname, lineno, msg, args, exc_info, func=None, sinfo=None)

包含与正在记录的事件相关的所有信息。

主要信息在 msgargs 中传递,它们使用 msg % args 组合以创建记录的 message 字段。

参数:
  • name – 用于记录由此LogRecord表示的事件的记录器的名称。请注意,此名称将始终具有此值,即使它可能由连接到不同(祖先)记录器的处理程序发出。
  • level – 记录事件的数字级别(DEBUG,INFO等之一)请注意,这将转换为LogRecord的 two 属性:数字值为 levelno,相应级别名称为 levelname
  • pathname – 执行日志记录调用的源文件的完整路径名。
  • lineno – 在进行日志调用的源文件中的行号。
  • msg – 事件描述消息,可能是带有变量数据占位符的格式字符串。
  • args – 将变量数据合并到 msg 参数中以获取事件描述。
  • exc_info – 具有当前异常信息的异常元组,如果没有异常信息可用,则为 None
  • func – 调用日志调用的函数或方法的名称。
  • sinfo – 一个文本字符串,表示当前线程中堆栈基址的堆栈信息,直到日志调用。
getMessage()

在将任何用户提供的参数与消息合并后,返回此 LogRecord 实例的消息。如果用户提供的记录调用的消息参数不是字符串,则会调用 str() 将其转换为字符串。这允许使用用户定义的类作为消息,其 __str__ 方法可以返回要使用的实际格式字符串。

在 3.2 版更改: 通过提供用于创建记录的工厂,使得 LogRecord 的创建更加可配置。工厂可以使用 getLogRecordFactory()setLogRecordFactory() 设置(参见工厂签名)。

此功能可用于在创建时将自己的值注入LogRecord。您可以使用以下模式:

old_factory = logging.getLogRecordFactory()

def record_factory(*args, **kwargs):
    record = old_factory(*args, **kwargs)
    record.custom_attribute = 0xdecafbad
    return record

logging.setLogRecordFactory(record_factory)

使用这种模式,可以链接多个工厂,并且只要它们不会覆盖彼此的属性或无意地覆盖上面列出的标准属性,就不会有任何惊喜。

16.6.7. LogRecord属性

LogRecord具有许多属性,其中大多数是从构造函数的参数派生的。 (请注意,名称并不总是完全对应于LogRecord构造函数参数和LogRecord属性之间。)这些属性可用于将记录中的数据合并到格式字符串中。下表列出了(按字母顺序)属性名称,其含义和%格式字符串中的相应占位符。

如果您使用{}格式化(str.format()),您可以使用 {attrname} 作为格式字符串中的占位符。如果使用$格式化(string.Template),请使用 ${attrname} 格式。在这两种情况下,当然,将 attrname 替换为要使用的实际属性名称。

在{}格式化的情况下,您可以通过将属性名称放在属性名称后面指定格式化标记,并用冒号分隔。例如:{msecs:03d} 的占位符会将 4 的毫秒值格式化为 004。有关可用选项的完整详细信息,请参阅 str.format() 文档。

属性名称

格式

描述

args

你不需要自己格式化。

参数的元组合并到 msg 中以产生 message,或者其值用于合并的字典(当只有一个参数时,它是字典)。

asctime

%(asctime)s

LogRecord 创建时的人工可读时间。默认情况下,它的格式为‘2003-07-08 16:49:45,896’(逗号后面的数字是毫秒部分的时间)。

created

%(created)f

创建 LogRecord 的时间(由 time.time() 返回)。

exc_info

你不需要自己格式化。

异常元组(或 sys.exc_info),如果没有发生异常,None

filename

%(filename)s

pathname 的文件名部分。

funcName

%(funcName)s

包含日志调用的函数的名称。

levelname

%(levelname)s

消息的文本记录级别('DEBUG''INFO''WARNING''ERROR''CRITICAL')。

levelno

%(levelno)s

消息的数字记录级别(DEBUGINFOWARNINGERRORCRITICAL)。

lineno

%(lineno)d

发出日志记录调用的源行号(如果可用)。

模块

%(module)s

模块(filename 的名称部分)。

msecs

%(msecs)d

创建 LogRecord 时的毫秒部分。

message

%(message)s

记录的消息,计算为 msg % args。这是在调用 Formatter.format() 时设置的。

msg

你不需要自己格式化。

在原始日志调用中传递的格式字符串。与 args 合并以生成 message 或任意对象(请参阅 使用任意对象作为消息)。

名称

%(name)s

用于记录呼叫的记录器的名称。

pathname

%(pathname)s

发出日志记录调用的源文件的完整路径名(如果可用)。

process

%(process)d

进程ID(如果可用)。

processName

%(processName)s

进程名称(如果可用)。

relativeCreated

%(relativeCreated)d

相对于加载日志记录模块的时间,创建LogRecord的时间(毫秒)。

stack_info

你不需要自己格式化。

堆栈帧信息(如果可用)从堆栈的底部在当前线程,直到并包括日志记录调用的堆栈帧导致此记录的创建。

thread

%(thread)d

线程ID(如果可用)。

threadName

%(threadName)s

线程名称(如果可用)。

在 3.1 版更改: 加入 processName

16.6.8. LoggerAdapter对象

LoggerAdapter 实例用于方便地将上下文信息传递到日志记录调用中。有关使用示例,请参阅 向记录输出添加上下文信息 一节。

class logging.LoggerAdapter(logger, extra)

返回使用基础 Logger 实例和类似dict的对象初始化的 LoggerAdapter 的实例。

process(msg, kwargs)

修改传递给记录调用的消息和/或关键字参数,以便插入上下文信息。这个实现将对象作为 extra 传递给构造函数,并使用关键’extra’将它添加到 kwargs。返回值是一个(msgkwargs)元组,它具有传入的参数的(可能已修改的)版本。

除了上述之外,LoggerAdapter 支持以下 Logger 的方法:debug()info()warning()error()exception()critical()log()isEnabledFor()getEffectiveLevel()setLevel()hasHandlers()。这些方法具有与其在 Logger 中的对应方相同的签名,因此您可以互换地使用这两种类型的实例。

在 3.2 版更改: isEnabledFor()getEffectiveLevel()setLevel()hasHandlers() 方法加入 LoggerAdapter 中。这些方法委托给底层的记录器。

16.6.9. 螺纹安全

日志模块旨在是线程安全的,无需任何特殊的工作,需要由其客户端完成。它实现了这一点,虽然使用线程锁;有一个锁定序列化对模块的共享数据的访问,并且每个处理程序还创建一个锁以串行化对其底层I/O的访问。

如果您使用 signal 模块实现异步信号处理程序,则可能无法在此类处理程序中使用日志记录。这是因为 threading 模块中的锁实现并不总是重入,因此不能从这种信号处理程序调用。

16.6.10. 模块级函数

除了上述类之外,还有许多模块级函数。

logging.getLogger(name=None)

返回具有指定名称的记录器,如果名称为 None,则返回一个记录器,它是层次结构的根记录器。如果指定,名称通常是点分隔的分层名称,如 ‘a’‘a.b’‘a.b.c.d’。这些名称的选择完全取决于使用日志记录的开发人员。

使用给定名称对此函数的所有调用都返回相同的记录器实例。这意味着记录器实例不需要在应用程序的不同部分之间传递。

logging.getLoggerClass()

返回标准 Logger 类或传递给 setLoggerClass() 的最后一个类。可以从新的类定义中调用此函数,以确保安装自定义的 Logger 类不会撤消已由其他代码应用的自定义。例如:

class MyLogger(logging.getLoggerClass()):
    # ... override behaviour here
logging.getLogRecordFactory()

返回用于创建 LogRecord 的可调用项。

3.2 新版功能: 此功能与 setLogRecordFactory() 一起提供,以允许开发人员更多地控制如何构建表示日志记录事件的 LogRecord

有关如何调用工厂的更多信息,请参阅 setLogRecordFactory()

logging.debug(msg, *args, **kwargs)

在根记录器上记录具有级别 DEBUG 的消息。 msg 是消息格式字符串,args 是使用字符串格式化运算符合并到 msg 中的参数。 (请注意,这意味着您可以使用格式字符串中的关键字以及单个字典参数。)

kwargs 中有三个关键字参数被检查:exc_info,如果它不评估为false,会导致异常信息被添加到日志消息。如果提供了异常元组(以 sys.exc_info() 返回的格式),则使用它;否则,调用 sys.exc_info() 以获取异常信息。

第二个可选的关键字参数是 stack_info,默认为 False。如果为true,则将堆栈信息添加到日志记录消息中,包括实际的日志调用。注意,这不是与通过指定 exc_info 显示的堆栈信息相同的堆栈信息:前者是从堆栈底部到当前线程中的日志记录调用的堆栈帧,而后者是关于已解绕的堆栈帧的信息,跟随异常,同时搜索异常处理程序。

您可以独立于 exc_info 指定 stack_info,例如只是展示你如何到达代码中的某一点,即使没有引发异常。堆栈帧在标题行后面打印:

Stack (most recent call last):

这模仿显示异常框架时使用的 Traceback (most recent call last):

第三个可选的关键字参数是 extra,它可以用于传递一个字典,用于填充为具有用户定义属性的日志记录事件创建的LogRecord的__dict__。然后可以根据需要使用这些自定义属性。例如,它们可以合并到记录的消息中。例如:

FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logging.warning('Protocol problem: %s', 'connection reset', extra=d)

将打印类似的东西:

2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset

extra 中传递的字典中的键不应与日志记录系统使用的键冲突。 (有关日志记录系统使用哪些键的更多信息,请参阅 Formatter 文档。)

如果您选择在记录的消息中使用这些属性,您需要小心谨慎。在上面的例子中,例如,Formatter 已经被设置有期望在LogRecord的属性字典中的“clientip”和“user”的格式字符串。如果缺少这些,则不会记录消息,因为会发生字符串格式化异常。所以在这种情况下,你总是需要通过这些键的 extra 字典。

虽然这可能很讨厌,但是此功能旨在用于特殊情况,例如多线程服务器,其中相同的代码在许多上下文中执行,并且出现的有趣条件取决于该上下文(例如远程客户端IP地址和已认证用户名,在上面的示例中)。在这种情况下,可能特定的 Formatter 将与特定的 Handler 一起使用。

3.2 新版功能: 添加了 stack_info 参数。

logging.info(msg, *args, **kwargs)

在根记录器上记录具有级别 INFO 的消息。参数被解释为 debug()

logging.warning(msg, *args, **kwargs)

在根记录器上记录具有级别 WARNING 的消息。参数被解释为 debug()

注解

有一个过时的函数 warn 在功能上与 warning 相同。由于 warn 已弃用,请不要使用 - 使用 warning

logging.error(msg, *args, **kwargs)

在根记录器上记录具有级别 ERROR 的消息。参数被解释为 debug()

logging.critical(msg, *args, **kwargs)

在根记录器上记录具有级别 CRITICAL 的消息。参数被解释为 debug()

logging.exception(msg, *args, **kwargs)

在根记录器上记录具有级别 ERROR 的消息。参数被解释为 debug()。异常信息被添加到日志消息中。这个函数只能从异常处理程序中调用。

logging.log(level, msg, *args, **kwargs)

在根记录器上记录具有级别 level 的消息。其他参数被解释为 debug()

注解

上述模块级的方便功能,它委托给根记录器,调用 basicConfig() 以确保至少有一个处理程序可用。因此,他们应该在线程中使用 not,在早于2.7.1和3.2的Python版本中,除非至少一个处理程序已添加到根记录器 before 线程启动。在早期版本的Python中,由于 basicConfig() 中的线程安全缺点,这可能(在极少的情况下)导致处理程序被多次添加到根记录器,这可能导致同一事件的多个消息。

logging.disable(lvl)

为所有优先于记录器自身级别的记录器提供覆盖级别 lvl。当需要暂时将记录输出在整个应用程序中下调时,此功能可能有用。其效果是禁用严重性为 lvl 及以下的所有日志调用,因此如果您使用值INFO调用它,则所有INFO和DEBUG事件将被丢弃,而严重性为WARNING及以上的那些事件将根据记录器的有效水平。如果调用 logging.disable(logging.NOTSET),它将有效地删除此覆盖级别,以便日志记录输出再次取决于单个记录器的有效级别。

logging.addLevelName(lvl, levelName)

lvl 级别与内部字典中的文本 levelName 关联,用于将数字级别映射到文本表示,例如,当 Formatter 格式化消息时。此功能也可用于定义自己的级别。唯一的限制是所使用的所有级别必须使用此函数注册,级别应该是正整数,并且它们应该按严重性的递增顺序增加。

注解

如果你正在考虑定义自己的水平,请参阅 自定义级别 部分。

logging.getLevelName(lvl)

返回日志记录级别 lvl 的文本表示。如果级别是预定义级别 CRITICALERRORWARNINGINFODEBUG 之一,那么您将获得相应的字符串。如果您有使用 addLevelName() 的名称的关联级别,则返回与 lvl 关联的名称。如果传入了对应于定义的级别之一的数值,则返回相应的字符串表示。否则,将返回字符串’Level%s’%lvl。

注解

级别是内部整数(因为它们需要在日志记录逻辑中进行比较)。此函数用于通过 %(levelname)s 格式说明符(参见 LogRecord属性)在整数级别和格式化日志输出中显示的级别名称之间进行转换。

在 3.4 版更改: 在3.4之前的Python版本中,此函数也可以传递文本级别,并返回级别的相应数值。这个未记录的行为被认为是一个错误,并在Python 3.4中删除,但恢复在3.4.2由于保留向后兼容性。

logging.makeLogRecord(attrdict)

创建并返回其属性由 attrdict 定义的新 LogRecord 实例。此函数对于获取一个经过酸洗的 LogRecord 属性字典,通过套接字发送,并在接收端将其重构为 LogRecord 实例非常有用。

logging.basicConfig(**kwargs)

通过创建具有默认 FormatterStreamHandler 并将其添加到根记录器,对日志系统进行基本配置。如果没有为根记录器定义处理程序,那么函数 debug()info()warning()error()critical() 将自动调用 basicConfig()

如果根记录器已经为其配置了处理程序,则此函数不执行任何操作。

注解

在启动其他线程之前,应该从主线程调用此函数。在2.7.1和3.2之前的Python版本中,如果从多个线程调用此函数,则可能(在极少数情况下)将一个处理程序多次添加到根记录器,导致意外的结果,例如消息被复制在日志中。

支持以下关键字参数。

格式

描述

filename

指定使用指定的文件名而不是StreamHandler创建FileHandler。

filemode

指定打开文件的模式,如果指定了filename(如果filemode未指定,则默认为’a’)。

format

对处理程序使用指定的格式字符串。

datefmt

使用指定的日期/时间格式。

style

如果指定了 format,请将此样式用于格式字符串。分别用于%格式,str.format()string.Template 的“%”,“{”或“$”之一,如果未指定,则默认为“%”。

level

将根记录器级别设置为指定的级别。

stream

使用指定的流初始化StreamHandler。注意,这个参数与’filename’不兼容 - 如果两者都存在,则产生一个 ValueError

handlers

如果指定,这应该是已经创建的处理程序添加到根记录器的迭代。任何没有格式化程序集的处理程序将被分配在此函数中创建的默认格式化程序。注意,这个参数与’filename’或’stream’不兼容 - 如果两者都存在,则引发 ValueError

在 3.2 版更改: 添加了 style 参数。

在 3.3 版更改: 添加了 handlers 参数。添加了额外的检查以捕获指定了不兼容参数的情况(例如 handlersstreamfilename,或 streamfilename 一起)。

logging.shutdown()

通知记录系统通过刷新和关闭所有处理程序来执行有序关闭。这应该在应用程序退出时调用,并且在此调用后不应进一步使用日志系统。

logging.setLoggerClass(klass)

告知日志记录系统在实例化记录器时使用类 klass。类应该定义 __init__(),使得只需要一个名称参数,__init__() 应该调用 Logger.__init__()。通常在任何记录器由需要使用自定义记录器行为的应用程序实例化之前调用此函数。

logging.setLogRecordFactory(factory)

设置用于创建 LogRecord 的可调用项。

参数:factory – 工厂可调用来实例化日志记录。

3.2 新版功能: 此功能与 getLogRecordFactory() 一起提供,以允许开发人员更多地控制如何构建表示日志记录事件的 LogRecord

工厂有以下签名:

factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, **kwargs)

name:

记录器名称。

level:

日志记录级别(数字)。

fn:

执行日志调用的文件的完整路径名。

lno:

在进行日志调用的文件中的行号。

msg:

日志消息。

args:

日志消息的参数。

exc_info:

异常元组或 None

func:

调用日志调用的函数或方法的名称。

sinfo:

traceback.print_stack() 提供的堆栈跟踪,显示调用层次结构。

kwargs:

其他关键字参数。

16.6.11. 模块级属性

logging.lastResort

通过此属性可以获得“最后手段的处理程序”。这是一个 StreamHandler 写入具有 WARNING 级别的 sys.stderr,用于在没有任何日志配置的情况下处理日志记录事件。最终结果是将消息打印到 sys.stderr。这将替换先前的错误消息,说“没有处理程序可以找到记录器XYZ”。如果由于某种原因需要较早的行为,则 lastResort 可以设置为 None

3.2 新版功能.

16.6.12. 与警告模块集成

captureWarnings() 功能可用于将 loggingwarnings 模块集成。

logging.captureWarnings(capture)

此功能用于通过登录和关闭来捕获警告。

如果 captureTrue,则 warnings 模块发出的警告将重定向到日志记录系统。具体来说,将使用 warnings.formatwarning() 格式化警告,并将生成的字符串记录到名为 'py.warnings' 且严重性为 WARNING 的记录器。

如果 captureFalse,则警告重定向到日志系统将停止,并且警告将重定向到其原始目标(即在调用 captureWarnings(True) 之前生效的目标)。

参见

模块 logging.config

日志模块的配置API。

模块 logging.handlers

有用的处理程序包括在日志模块中。

PEP 282 - 记录系统

描述此功能以包含在Python标准库中的提案。

原始Python日志记录包

这是 logging 包的原始来源。此网站提供的软件包版本适用于Python 1.5.2,2.1.x和2.2.x,它们不包括标准库中的 logging 软件包。