basicConfig只能在根记录器上使用,处理程序/格式化程序只能在命名的记录器上使用



我正在处理日志记录,有一个问题。

我知道有简单和高级的日志记录概念。

在简单的日志记录中,我们有logging.info(),等等,而在高级日志记录中,我们有logging.getlogger(some_name).

在简单日志记录中,我们可以使用logging. basicConfig配置日志路径和 msg 格式,而在高级日志记录的情况下,我们有格式化程序的概念,处理程序分配给通过使用logging.getlogger(some_name).addhandlers..获得的记录器

。我们甚至可以使用logging.getlogger().addhandlers....将多个处理程序添加到根记录器中

因此,高级日志记录的唯一好处是我们可以将记录器名称添加到硬编码值或__name__相应的模块值。

因此,由于格式化程序和处理程序可以用于简单和高级日志记录方法,简单意味着根记录器和高级意味着模块名称记录器吗?

basicConfig 只能用于根记录器,处理程序/格式化程序只能在命名记录器上使用吗?

建议


首先,简单和复杂(或基本和高级)是相对术语。您可以只使用具有非常复杂日志记录配置的根记录器,您会将其称为简单日志记录吗,因为您使用的是根记录器?哈哈你不应该将相对术语(如基本和高级)的语义(含义)与 Python 对象联系起来。语言结构的语义要么由它们引起的计算来表示,要么由它们产生的效果来表示,这对每个人来说总是相同的。

词汇


其次,让我们澄清几个术语。

  • logging是一个 Pythonmodule

  • basicConfiggetLogger是模块级函数。

  • debug()info()warning()都是模块级函数和类方法,这取决于你如何调用它们。如果执行logging.debug(msg)则调用模块级函数,如果执行some_logger.debug(msg)则调用方法。模块级函数本身也调用底层的根方法。

执行流程层次结构


root记录器是在您导入日志记录机制时自动创建的,即当您执行import logging时 -root记录器会自动创建,这反过来又使您能够执行使用该根记录器的简单调用,例如logging.debug()

基本上,模块级函数如下所示:

def debug(msg, *args, **kwargs):
"""
Log a message with severity 'DEBUG' on the root logger. If the logger has
no handlers, call basicConfig() to add a console handler with a pre-defined
format.
"""
if len(root.handlers) == 0:
basicConfig()
root.debug(msg, *args, **kwargs)

记录器按层次结构进行组织,所有记录器都是root记录器的后代。

当您调用getLogger(name)name是否存在时,它将返回该logger,如果没有,它将创建该loggergetLogger(name)函数是幂等的,这意味着,对于具有相同名称的后续调用,无论您调用多少次,它都会返回该现有记录器。

该名称可能是句点分隔的层次结构值,如foo.bar.baz。在分层列表中靠后位置的记录器是列表中较高位置的记录器的子级。例如,给定一个名称为foo的记录器,名称为foo.barfoo.bar.bazfoo.bam的记录器都是foo的后代。

创建记录器时,级别设置为 NOTSET(当记录器是非 root 记录器时,这将导致所有消息委托给父级)。这意味着,如果记录器的级别为 NOTSET,则会遍历其祖先记录器链,直到找到级别不是 NOTSET 的祖先,或者到达根。

在不深入细节的情况下,这里是相关链接:记录器对象、模块级函数、执行流程。

您的问题


在简单日志记录中,我们可以使用以下方法配置日志路径和 msg 格式 伐木。basicConfig,而在高级日志记录的情况下,我们有 格式化程序的概念,分配给记录器的处理程序 通过使用 logging.getlogger(some_name).addhandlers.. 获得。

不。

正如我们现在所知,basicConfig是一个模块级函数。此函数为您的日志记录系统设置基本配置,应该先调用,因为如果您在自己调用之前执行任何类型的日志记录,如果没有为根记录器定义处理程序,则debug()info()等函数将自动调用basicConfig()。这个函数也是幂等的,这意味着一旦你调用它一次,你可以在没有效果之后调用它十亿次。但是,此调用将确定您的日志记录将如何适用于所有记录器,而不仅仅是根(因为所有记录器都通过层次结构连接)并将消息从一个传递到另一个,除非您为后代记录器指定显式配置。

路径是您希望记录日志消息的位置,这是通过处理程序设置的,它可以是控制台、文件、电子邮件等等......在此处查看完整列表。

格式是您希望消息的显示方式,您希望它们包含的信息类型,这是通过格式化程序完成的,您可以在格式化程序中提供所需的日志记录属性。这些属性确定日志记录知道哪些信息。

这一切都是共同作用的。Handlers附加到loggersformatters附加到handlers。您可以通过 basicConfig 或 dictConfig 或 fileConfig 为每个应用程序设置一次,也可以按logger单独设置这些。

因此,高级日志记录的唯一好处是我们可以 将记录器名称添加到硬编码值或命名是相应的模块值。

不。

更复杂的日志记录意味着您可以将应用程序拆分为模块,并为每个模块提供单独的loggers,并拥有一个非常精细的消息系统,其中应用程序的每个部分都记录不同的东西(您希望敏感部分记录非常具体的信息,并可能通过电子邮件快速发送它们或将它们记录到文件中),而您希望琐碎的部分轻松记录并通过控制台打印它们。

基本配置只能用于根记录器和处理程序/格式化程序吗 只用于命名的博客?

basicConfig将为root记录器设置配置,除非另有说明,否则所有记录器都将使用该配置。


import logging
root = logging.getLogger()
print(root.handlers)  # no handlers at this point
logging.warning('hello')  # calls basicConfig
print(root.handlers)  # has handler now
# create file handler
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.ERROR)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
# add the handlers to the logger
root.addHandler(fh)
print(root.handlers)  # now has 2 handlers
root.warning('whats good')  # will only show to console
root.error('whats good')  # will show to console and file
random_logger = logging.getLogger('bogus')  # another logger, descendant from root
random_logger.warning('im random')  # will use root handlers, meaning it will show to console
random_logger.error('im random error')  # same as above, both console and file
# and you can ofc add handlers and what not differently to this non root logger

相关内容

最新更新