我正在记录日志,并且有一个问题。
我知道有简单和高级的日志记录概念。
在简单日志记录中,我们有logging.info()
,而在高级日志记录中,我们有logging.getlogger(some_name)
。
在简单日志记录中,我们可以使用logging.
basicConfig
配置日志路径和msg格式,而在高级日志记录的情况下,我们具有格式化程序的概念,即使用logging.getlogger(some_name).addhandlers..
分配给记录程序的处理程序
我们甚至可以使用logging.getlogger().addhandlers....
将多个处理程序添加到根记录器中
因此,高级日志记录的唯一好处是我们可以将记录器名称添加到硬编码值或添加到相应模块值的__name__
中。
因此,既然格式化程序和处理程序可以在简单和高级日志记录方法中使用,那么简单的均值根记录器和高级的均值模块名称记录器是否可用?
basicConfig只能在根记录器上使用,而处理程序/格式化程序只能在命名记录器上使用吗?
最佳答案
忠告
首先,简单和复杂(或基本和高级)是相对术语。您可能只拥有具有非常复杂的日志记录配置的root记录器,因为使用了root记录器,您将之称为简单记录吗?不。您不应该将诸如基本和高级之类的相对术语的语义(含义)与Python对象联系在一起。语言构造的语义通过它们引起的计算或它们产生的效果来表示,这对于每个人来说都是相同的。
词典
其次,让我们澄清一些术语。logging
是Python module
。basicConfig
和getLogger
是模块级功能。debug()
,info()
,warning()
等都是模块级函数和类方法,具体取决于您如何调用它们。如果您执行logging.debug(msg)
,则在调用模块级函数,如果您执行some_logger.debug(msg)
,则在调用方法。模块级别的函数本身也会在后台调用root方法。
执行流程和层次结构
导入日志记录机器时即自动创建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
,如果不存在,它将创建该logger
。 getLogger(name)
函数是幂等的,这意味着对于后续的同名调用,无论您调用多少次,它都将仅返回该现有记录器。该名称可能是句点分隔的分层值,例如
foo.bar.baz
。层次结构列表中位于最下方的记录器是列表中较高位置的记录器的子级。例如,给定名称为foo
的记录器,名称为foo.bar
,foo.bar.baz
和foo.bam
的记录器都是foo
的后代。创建记录器时,级别设置为NOTSET(当该记录器是非root记录器时,这会将所有消息委派给父级)。这意味着,如果记录器具有NOTSET级别,则遍历其祖先记录器链,直到找到非NOTSET级别的祖先或到达根为止。
在不深入细节的情况下,以下是相关链接:logger objects,module level functions,flow of execution。
你的问题
在简单的日志记录中,我们可以使用以下命令配置日志路径和味精格式
记录。 basicConfig,而在进行高级日志记录的情况下,
格式化程序的概念,分配给记录器的处理程序
通过使用logging.getlogger(some_name).addhandlers获得。
没有。
众所周知,basicConfig是模块级别的功能。此函数为您的日志记录系统设置了基本配置,应该在其他任何东西之前调用,因为如果在调用自己之前进行任何类型的日志记录,则
debug()
,info()
等函数会自动调用basicConfig()
如果没有为根记录器定义处理程序。此函数也是幂等的,这意味着一旦调用一次,就可以调用十亿次,而没有任何效果。但是此调用将确定您的日志记录将如何对所有记录器起作用,而不仅仅是根(因为所有记录器都通过层次结构连接),并将消息从一个传递到另一个,除非您为后代记录器指定显式配置。该路径是您希望记录日志消息的位置,它是通过handlers设置的,可以是控制台,文件,电子邮件,等等...参见complete list here。
该格式是您希望消息显示的方式,希望它们包含的信息类型,并且通过formatters(在其中提供所需的log record attributes)完成。这些属性确定日志记录知道哪些信息。
但这一切都可以一起工作。
Handlers
连接到loggers
,并且formatters
连接到handlers
。您可以通过basicConfig或dictConfig或fileConfig在整个应用程序中设置一次,也可以根据logger
分别设置。因此,高级日志记录的唯一好处是我们可以
将记录器名称添加到硬编码值或命名哪个
是各自的模块值。
没有。
更复杂的日志记录意味着您可以将应用程序拆分为模块,每个模块具有单独的
loggers
,并具有非常完善的消息系统,其中应用程序的每个部分都记录不同的内容(您希望敏感部分记录非常具体的内容)信息,也许可以通过电子邮件将其快速发送或记录到文件中),而您希望琐碎的部分可以轻松记录并仅通过控制台进行打印。basicConfig只能用于root记录器和处理程序/格式化程序
仅用于命名记录器?
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
关于python - basicConfig只能在根记录器上使用,而处理程序/格式化程序只能在命名记录器上使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57797876/