如何在 Python 中使用多记录器

How to use multi logger in 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

我可以看到他们的水平是正确的,但他们两个表现得好像水平是错误的。

如何正确配置它们?

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

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,默认情况下它是一个具有警告级别的 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 return 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")