Как использовать multi logger в Python

#python #logging #python-logging

#python #ведение журнала #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")

  

Вывод:
Выходной результат

Я вижу, что их уровень правильный, но оба они действуют так, как будто уровень является ОШИБКОЙ.

Как я могу их правильно настроить?

Ответ: Основываясь на советах blues, я добавил обработчик, и он решил мою проблему. Вот измененный код:

 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")
  

Ответ №1:

Ни у def_logger, ни у любого из его родителей нет привязанного к нему обработчика. Итак, что происходит, так это то, что модуль ведения журнала возвращается к logging.lastResort которому по умолчанию является обработчиком потока с предупреждением об уровне. Именно по этой причине информационное сообщение не отображается, а ошибка появляется. Итак, чтобы решить вашу проблему, прикрепите обработчик к def_logger.

Примечание: В вашем сценарии единственным родителем обоих регистраторов является корневой обработчик по умолчанию.

Комментарии:

1. Мне это ясно. Похоже, я неправильно понимаю концепцию обработчика и регистратора.

Ответ №2:

Вы можете добавить 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 , запись журнала обрабатывается. В противном случае он пропускается.

Примечание:

  • Фильтр, прикрепленный к a logger , не будет вызываться для записи журнала, сгенерированной регистраторами-потомками. Например, если вы добавите фильтр в logger A , он не будет вызываться для записей, которые генерируются logger A.B nor A.B.C .

  • Фильтр, прикрепленный к a handler , просматривается до того, как событие будет отправлено этим обработчиком.

Это означает, что вам просто нужен один logger и добавьте два handler s с разными фильтрами.

 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")