python日志处理程序中setLevel的重点是什么?

时间:2013-07-16 05:26:22

标签: python logging

我们说我有以下代码:

import logging
import logging.handlers

a = logging.getLogger('myapp')
h = logging.handlers.RotatingFileHandler('foo.log')
h.setLevel(logging.DEBUG)
a.addHandler(h)

# The effective log level is still logging.WARN
print a.getEffectiveLevel() 
a.debug('foo message')
a.warn('warning message')

我希望在处理程序上设置logging.DEBUG会导致将调试级别的消息写入日志文件。但是,这会打印30作为有效级别(等于logging.WARNING,默认值),并且只将warn消息记录到日志文件中,而不是调试消息。

处理程序的日志级别似乎被丢弃在地板上,例如它被默默地忽略了。这让我很奇怪,为什么在处理程序上有setLevel呢?

4 个答案:

答案 0 :(得分:41)

它允许更精细的控制。默认情况下,根记录器具有WARNING级别设置,这意味着它不会打印较低级别的消息(无论处理程序的级别如何设置!)。但是,如果将根记录器的级别设置为DEBUG,则确实将消息发送到日志文件:

import logging
import logging.handlers

a = logging.getLogger('myapp')
a.setLevel(logging.DEBUG)   # set root's level
h = logging.handlers.RotatingFileHandler('foo.log')
h.setLevel(logging.DEBUG)
a.addHandler(h)
print a.getEffectiveLevel() 
a.debug('foo message')
a.warn('warning message')

现在,您想添加一个不记录调试信息的新处理程序的图像。 您只需设置处理程序日志记录级别即可完成此操作:

import logging
import logging.handlers

a = logging.getLogger('myapp')
a.setLevel(logging.DEBUG)   # set root's level

h = logging.handlers.RotatingFileHandler('foo.log')
h.setLevel(logging.DEBUG)
a.addHandler(h)

h2 = logging.handlers.RotatingFileHandler('foo2.log')
h2.setLevel(logging.WARNING)
a.addHandler(h2)

print a.getEffectiveLevel() 
a.debug('foo message')
a.warn('warning message')

现在,日志文件foo.log将包含这两个消息,而文件foo2.log将只包含警告消息。您可能对只有错误级别消息的日志文件感兴趣,然后只需添加Handler并将其级别设置为logging.ERROR,所有内容都使用相同的Logger

您可能会将Logger日志记录级别视为对给定记录器及其处理程序哪些消息“感兴趣”的全局限制。记录器之后考虑的消息将发送给处理程序,处理程序执行自己的过滤和日志记录过程。

答案 1 :(得分:19)

在Python日志记录中,有两个不同的概念:记录器记录的级别和处理程序实际激活的级别。

当进行日志调用时,基本上发生的是:

if self.level <= loglevel:
    for handler in self.handlers:
        handler(loglevel, message)

然后,每个处理程序将调用:

if self.level <= loglevel:
    # do something spiffy with the log!

如果您想要真实地演示此内容,可以查看Django's config settings。我会在这里提供相关代码。

LOGGING = {
    #snip
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'logging.NullHandler',
        },
        'console':{
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        }
    },
    'loggers': {
        #snip
        'myproject.custom': {
            # notice how there are two handlers here!
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}

因此,在上面的配置中,只有getLogger('myproject.custom').info及以上的日志才会被处理以进行记录。当发生这种情况时,控制台将输出所有结果(它将输出所有结果,因为它设置为DEBUG级别),而mail_admins记录器将发生在所有ERROR s,{ {1}}和FATAL s。

我想一些不是Django的代码也可能有所帮助:

CRITICAL

结果是:

import logging.handlers as hand
import logging as logging

# to make things easier, we'll name all of the logs by the levels
fatal = logging.getLogger('fatal')
warning = logging.getLogger('warning')
info = logging.getLogger('info')

fatal.setLevel(logging.FATAL)
warning.setLevel(logging.WARNING)
info.setLevel(logging.INFO)    

fileHandler = hand.RotatingFileHandler('rotating.log')

# notice all three are re-using the same handler.
fatal.addHandler(fileHandler)
warning.addHandler(fileHandler)
info.addHandler(fileHandler)

# the handler should log everything except logging.NOTSET
fileHandler.setLevel(logging.DEBUG)

for logger in [fatal,warning,info]:
    for level in ['debug','info','warning','error','fatal']:
        method = getattr(logger,level)
        method("Debug " + logger.name + " = " + level)

# now, the handler will only do anything for *fatal* messages...
fileHandler.setLevel(logging.FATAL)

for logger in [fatal,warning,info]:
    for level in ['debug','info','warning','error','fatal']:
        method = getattr(logger,level)
        method("Fatal " + logger.name + " = " + level)

再次注意Debug fatal = fatal Debug warning = warning Debug warning = error Debug warning = fatal Debug info = info Debug info = warning Debug info = error Debug info = fatal Fatal fatal = fatal Fatal warning = fatal Fatal info = fatal info在日志处理程序设置为{{1}时infowarningerrorfatal的内容但是,当处理程序设置为DEBUG时,突然只有FATAL条消息进入文件。

答案 2 :(得分:13)

处理程序代表记录事件的不同受众。处理程序的级别用于控制特定受众看到的输出的详细程度,并将另外用于记录器上设置的任何级别。记录器的级别用于控制从应用程序或库的不同部分进行日志记录的总体详细程度。

有关如何处理日志记录事件的详细信息,请参阅this diagram

enter image description here

答案 3 :(得分:0)

规则

当且仅当

handler.level <= message.level
&&
logger.level <= message.level

然后打印消息。

提醒:值越小越详细

Level    | Numeric value
---------|--------------
CRITICAL | 50
ERROR    | 40
WARNING  | 30
INFO     | 20
DEBUG    | 10
NOTSET   | 0

ref:https://docs.python.org/3/library/logging.html#logging-levels

换句话说

如果记录器设置为WARNING,则处理程序是否具有更详细的设置也无关紧要。它会在到达处理程序时被过滤掉。

完整示例

import logging


handler_info = logging.StreamHandler()
handler_info.setLevel("INFO")
handler_info.setFormatter(logging.Formatter(
    f"%(levelname)s message for %(name)s handled by handler_info: %(message)s"))

handler_debug = logging.StreamHandler()
handler_debug.setLevel("DEBUG")
handler_debug.setFormatter(logging.Formatter(
    f"%(levelname)s message for %(name)s handled by handler_debug: %(message)s"))

logger_info = logging.getLogger('logger_info')
logger_info.setLevel("INFO")
logger_info.addHandler(handler_info)
logger_info.addHandler(handler_debug)

logger_debug = logging.getLogger('logger_debug')
logger_debug.setLevel("DEBUG")
logger_debug.addHandler(handler_info)
logger_debug.addHandler(handler_debug)

print()
print("output for `logger_info.info('hello')`")
logger_info.info("hello")
print()
print("output for `logger_info.debug('bonjour')`")
logger_info.debug("bonjour")
print()
print("output for `logger_debug.info('hola')`")
logger_debug.info("hola")
print()
print("output for `logger_debug.debug('ciao')`")
logger_debug.debug("ciao")
print()

给出

output for `logger_info.info('hello')`
INFO message for logger_info handled by handler_info: hello
INFO message for logger_info handled by handler_debug: hello

output for `logger_info.debug('bonjour')`
# nothing, because message.level < logger.level

output for `logger_debug.info('hola')`
INFO message for logger_debug handled by handler_info: hola
INFO message for logger_debug handled by handler_debug: hola

output for `logger_debug.debug('ciao')`
DEBUG message for logger_debug handled by handler_debug: ciao
# nothing from handler_info, because message.level < handler.level