basicConfig 只能用于 root logger 而 handlers/formatter 只能用于 namedloggers 吗?

Can basicConfig only be used on root logger and handlers/formatter only be used on namedloggers?

我正在使用日志记录并有一个问题。

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

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

在简单的日志记录中,我们可以使用 logging. basicConfig 配置日志路径和消息格式,而在高级日志记录的情况下,我们有格式化程序的概念,分配给使用 [= 获得的记录器的处理程序14=]

我们甚至可以使用 logging.getlogger().addhandlers....

向根记录器添加多个处理程序

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

既然格式化程序和处理程序既可以用于简单日志记录方法,也可以用于高级日志记录方法,那么简单是指根记录器,高级是指模块名称记录器吗?

basicConfig 只能用在 root logger 上并且 handlers/formatter 只能用在 namedloggers 上吗?

忠告


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

词典


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

  • logging 是一个 Python module.

  • basicConfig & getLogger 是模块级函数。

  • debug()info()warning()都是模块级函数,class 方法,具体取决于您如何调用它们。如果你做 logging.debug(msg) 你调用模块级函数,如果你做 some_logger.debug(msg) 你调用一个方法。模块级函数本身也在幕后调用根方法。

执行流程 & 层次结构


当您导入日志机器时,root 记录器会自动创建,即当您执行 import logging - root 记录器会自动创建,这反过来又使您能够直接调用 logging.debug(),它使用 that 根记录器。

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

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 存在,它会 return 那个 logger,如果不存在,它会创建那个 loggergetLogger(name) 函数是 idempotent,这意味着,对于具有相同名称的后续调用,无论您调用多少次,它都会 return 现有的记录器。

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

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

无需深入了解细节,这里是相关链接:logger objects, module level functions, flow of execution

您的问题


In simple logging, we can configure the log path and msg format using logging. basicConfig whereas in case of advanced logging we have the concept of a formatter, handler which is assigned to the logger obtained by using logging.getlogger(some_name).addhandlers..

没有

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

路径 是您希望记录日志消息的位置,这是通过 handlers and it can be the console, a file, an email, whatever... see a complete list here.

设置的

格式 是您希望邮件显示的方式,您希望它们包含什么样的信息,这可以通过您想要的 formatters, where you provide the log record attributes 完成。这些属性决定了日志记录知道哪些信息。

但是这所有一起工作Handlers 附加到 loggersformatters 附加到 handlers。您可以通过 basicConfigdictConfigfileConfig 为您的整个应用程序设置一次,或者您可以单独设置这些,每个logger.

So the only benefit of advanced logging is the possibility for us to add the logger name either to a hardcoded value or to name which is respective module value.

没有

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

Can basicConfig only be used on root logger and handlers/formatter only be used on namedloggers?

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