#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
, не будет вызываться для записи журнала, сгенерированной регистраторами-потомками. Например, если вы добавите фильтр в loggerA
, он не будет вызываться для записей, которые генерируются loggerA.B
norA.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")