[英]How to avoid root handler being called from the custom logger in Python?
I have a basic config for the logging module with debug level - now I want to create another logger with error level only.我有一个具有调试级别的日志记录模块的基本配置 - 现在我只想创建另一个具有错误级别的记录器。 How can I do that?我怎样才能做到这一点?
The problem is that the root handler is called in addition to the error-handler - this is something I want to avoid.问题是除了错误处理程序之外还调用了根处理程序 - 这是我想要避免的事情。
import logging
fmt = '%(asctime)s:%(funcName)s:%(lineno)d:%(levelname)s:%(name)s:%(message)s'
logging.basicConfig(level=logging.DEBUG, format=fmt)
logger = logging.getLogger('Temp')
logger.setLevel(logging.ERROR)
handler = logging.StreamHandler()
handler.setLevel(logging.ERROR)
logger.addHandler(handler)
logger.error('boo')
The above code prints boo twice while I expect once only, and I have no idea what to do with this annoying issue...上面的代码打印了两次 boo,而我只期望一次,我不知道如何处理这个烦人的问题......
In [4]: logger.error('boo')
boo
2021-04-26 18:54:24,329:<module>:1:ERROR:Temp:boo
In [5]: logger.handlers
Out[5]: [<StreamHandler stderr (ERROR)>]
root
logger: the superior of superiors, does all the things that a normal logger does but doesn't pass the received log to anyone else. root
logger:上级中的上级,做普通 logger 所做的所有事情,但不会将收到的日志传递给其他任何人。handler
: a private contractor of a logger, who actually does anything with the log, eg. handler
:记录器的私人承包商,他实际上对日志做任何事情,例如。 formats the log, writes it to a file or stdout
, or sends it through tcp/udp.格式化日志,将其写入文件或stdout
,或通过 tcp/udp 发送。formatter
: a theme, a design that the handler
applies to the log. formatter
:主题, handler
应用于日志的设计。basicConfig
: a shortcut way to config the root
logger. basicConfig
:配置root
记录器的快捷方式。 This is useful when you want him to do all the job and all his lower rank loggers would just pass the log to him.当您希望他完成所有工作并且他的所有较低级别的伐木工只会将日志传递给他时,这很有用。basicConfig
sets root
logger's level to WARNING
and add a StreamHandler
that output the log to stderr
.在没有参数的情况下, basicConfig
将root
记录器的级别设置为WARNING
并将 output 日志添加到stderr
的StreamHandler
。format
and used a shortcut basicConfig
to config the root
logger.您创建了一种format
并使用快捷方式basicConfig
来配置root
记录器。 You want the root logger to do all the actual logging things您希望根记录器执行所有实际的记录操作Temp
您创建了一个新的低等级记录器Temp
ERROR
level and above.您希望它只接受ERROR
级别及以上的日志。StreamHandler
.您创建了另一个StreamHandler
。 Which output to stdout
by default.其中 output 默认为stdout
。ERROR
level and above您希望它只处理ERROR
级别及以上Temp
logger, which made 5.
redundant since the level is set in 3.
哦,你把它分配给了Temp
记录器,这使得5.
多余,因为级别设置为3.
root
logger to do the job since 1.
!哦等等,以为你只是想让root
记录器从1.
开始就完成这项工作。!ERROR
with your logger.您使用记录器记录了一个ERROR
。Your Temp
logger accepted a string boo
at ERROR
level.您的Temp
记录器接受了ERROR
级别的字符串boo
。 Then told its handler to process the string.然后告诉它的处理程序处理字符串。 Since this handler didn't have any formatter
assigned to it, it outputted the string as-is to stdout
: boo
由于该处理程序没有分配任何formatter
,因此它按原样将字符串输出到stdout
: boo
After that, Temp
logger passed the string boo
to his superior, the root
logger.之后, Temp
记录器将字符串boo
传递给他的上级,即root
记录器。
The root
logger accepted the log since the log level is ERROR
> WARNING
.由于日志级别为ERROR
> WARNING
,因此root
记录器接受了日志。 The root
logger then told its handler to process the string boo
.然后root
记录器告诉其处理程序处理字符串boo
。 This handler apply the format string to boo
.此处理程序将格式字符串应用于boo
。 Add timestamp, add location, add the name of logger that passed the log, etc.添加时间戳,添加位置,添加通过日志的记录器的名称等。
Finally it outputted the result to stderr
: 2021-04-26 18:54:24,329:<module>:1:ERROR:Temp:boo
最后将结果输出到stderr
: 2021-04-26 18:54:24,329:<module>:1:ERROR:Temp:boo
Since your code does exactly what you tell it to do, you have to tell it as much detail as possible.由于您的代码完全按照您的要求执行,因此您必须尽可能详细地告诉它。
basicConfig
when you are lazy.只有在你懒惰的时候才使用basicConfig
。 By removing basicConfig
line, your problem solved.通过删除basicConfig
行,您的问题解决了。logger = logging.getLogger('__name__')
so that the logger has the name of the module.使用logger = logging.getLogger('__name__')
以便记录器具有模块的名称。 Looking at the log and know exactly which import path
that it came from.查看日志并确切知道它来自哪个import path
。propagate
property.决定一个记录器是应该为它自己保留日志还是通过propagate
属性将它传递到链上。 In your case, logger.propagate = False
also solves the problem.在您的情况下, logger.propagate = False
也可以解决问题。root
and let the root do the actual logging.在实践中,您不应该将处理程序添加到您的记录器,而只是让记录器将日志一直传递给root
并让根执行实际的日志记录。 Why?为什么?
propagating=False
.您可以通过propagating=False
完全关闭特定记录器的日志记录。root
logger.如果您只将它们添加到root
记录器,您就可以准确地知道代码中的所有处理程序和格式化程序。 You have a centralized control over the logging.您可以集中控制日志记录。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.