如何在Python中使用多重记录器

问题描述

我尝试使用两种不同的记录器来处理不同的日志级别。例如,我希望信息消息存储在文件中,并且不记录错误消息。某些特殊功能错误消息将通过电子邮件发送给用户

我编写了一个简单的程序来测试日志记录模块。

代码

import logging

def_logger = logging.getLogger("debuglogger")
def_logger.setLevel(logging.DEBUG)

maillogger = logging.getLogger("mail")
maillogger.setLevel(logging.ERROR)
mailhandler = logging.StreamHandler()
mailhandler.setLevel(logging.ERROR)
mailhandler.setFormatter(logging.Formatter('Error:  %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
maillogger.addHandler(mailhandler)


print(def_logger.getEffectiveLevel())
print(maillogger.getEffectiveLevel())
def_logger.info("info 1")
maillogger.info("info 2")
def_logger.error("error 1")
maillogger.error("error 2")

输出Output result

我可以看到它们的级别是正确的,但是它们的行为都像是ERROR。

如何正确配置它们?

答案:根据布鲁斯的建议,我添加一个处理程序,它解决了我的问题。 这是修改后的代码

import logging

def_logger = logging.getLogger("debuglogger")
def_logger.setLevel(logging.DEBUG)
def_logger.addHandler(logging.StreamHandler()) #added a handler here

maillogger = logging.getLogger("mail")
maillogger.setLevel(logging.ERROR)
mailhandler = logging.StreamHandler()
mailhandler.setLevel(logging.ERROR)
mailhandler.setFormatter(logging.Formatter('Error:  %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
maillogger.addHandler(mailhandler)


print(def_logger.getEffectiveLevel())
print(maillogger.getEffectiveLevel())
def_logger.info("info 1")
maillogger.info("info 2")
def_logger.error("error 1")
maillogger.error("error 2")

解决方法

def_logger及其任何父母均未附加处理程序。因此,发生的情况是日志记录模块回退到logging.lastResort,默认情况下,该模块是级别为Warning的StreamHandler。这就是为什么信息消息没有出现而错误消息却出现的原因。因此,要解决您的问题,请将处理程序附加到def_logger。

注意:在您的方案中,两个记录器唯一拥有的父级是默认的根处理程序。

,

您可以为每个记录器或处理程序添加一个filter以仅处理感兴趣的记录

import logging


def filter_info(record):
    return True if record.levelno == logging.INFO else False


def filter_error(record):
    return True if record.levelno >= logging.ERROR else False


# define debug logger
def_logger = logging.getLogger("debuglogger")
def_logger.setLevel(logging.DEBUG)
def_logger.addFilter(filter_info)               # add filter directly to this logger since you didn't define any handler 

# define handler for mail logger
mail_handler = logging.StreamHandler()
mail_handler.setLevel(logging.ERROR)
mail_handler.setFormatter(logging.Formatter('Error:  %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
mail_handler.addFilter(filter_error)            # add filter to handler 

mail_logger = logging.getLogger("mail")
mail_logger.setLevel(logging.ERROR)
mail_logger.addHandler(mail_handler)

# test
def_logger.info("info 1")
mail_logger.info("info 2")
def_logger.error("error 1")
mail_logger.error("error 2")

如果filter返回True,则处理日志记录。否则,它将被跳过。

注意:

    由后代记录器生成的日志记录不会调用附加到logger
  • 过滤器。例如,如果您向记录器A添加过滤器,则记录器A.BA.B.C生成的记录都不会调用该过滤器。

  • 在该处理程序发出事件之前,请先咨询
  • 附加到handler的过滤器。

这意味着您只需要一个logger并添加两个handler,并附加了不同的过滤器即可。

import logging


def filter_info(record):
    return True if record.levelno == logging.INFO else False


def filter_error(record):
    return True if record.levelno >= logging.ERROR else False


# define your logger
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)

# define handler for file
file_handler = logging.FileHandler('path_to_log.txt')
file_handler.level = logging.INFO
file_handler.addFilter(filter_info)      # add filter to handler

# define handler for mail
mail_handler = logging.StreamHandler()
mail_handler.setLevel(logging.ERROR)
mail_handler.setFormatter(logging.Formatter('Error:  %(asctime)s - %(name)s - %(levelname)s - %(message)s'))
mail_handler.addFilter(filter_error)     # add filter to handler

logger.addHandler(file_handler)
logger.addHandler(mail_handler)

# test
logger.info("info 1")
logger.info("info 2")
logger.error("error 1")
logger.error("error 2")