Вывод данных для сборки в Python-протоколировании MemoryHandler с SMTPHandler

У меня есть модуль протоколирования MemoryHandler, настроенный для отладки очереди и сообщений об ошибках для целевой SMTPHandler. Я хочу, чтобы электронное письмо отправлялось при ошибках процесса, содержащих все операторы отладки до этой точки (по одной в строке). Вместо этого я получаю отдельное письмо для каждого отладочного сообщения.

Кажется, что это должно быть тривиальным и частью пакета протоколирования, но я ничего не могу найти об этом, никаких примеров, ничего в Google.

log = logging.getLogger()
log.setLevel(logging.DEBUG)
debug_format = logging.Formatter("%(levelname)s at %(asctime)s in %(filename)s (line %(lineno)d):: %(message)s")

# write errors to email
error_mail_subject = "ERROR: Script error in %s on %s" % (sys.argv[0], os.uname()[1])
error_mail_handler = logging.handlers.SMTPHandler(SMTP_HOST, '[email protected]'+os.uname()[1], [LOG_EMAIL], error_mail_subject)
error_mail_handler.setLevel(logging.ERROR)
#error_mail_handler.setLevel(logging.DEBUG)
error_mail_handler.setFormatter(debug_format)

# buffer debug messages so they can be sent with error emails
memory_handler = logging.handlers.MemoryHandler(1024*10, logging.ERROR, error_mail_handler)
memory_handler.setLevel(logging.DEBUG)

# attach handlers
log.addHandler(memory_handler)
log.addHandler(error_mail_handler)

В связи с этим:

Нужно ли добавлять тег error_mail_handler в журнал, если это цель memory_handler? Должно ли error_mail_handler быть установлено значение DEBUG или ERROR? Нужна ли даже цель, когда она подается от memory_handler?

Хотелось бы увидеть какой-нибудь рабочий код от тех, кто решил эту проблему.

Ответы

Ответ 1

Вы можете использовать или адаптировать BufferingSMTPHandler, который находится в этот тест script.

В общем случае вам не нужно добавлять обработчик в регистратор, если он является объектом обработчика MemoryHandler, который был добавлен в регистратор. Если вы установите уровень обработчика, это повлияет на то, что обработчик фактически обрабатывает, - он не будет обрабатывать что-либо менее серьезное, чем его уровень.

Ответ 2

Я написал свою собственную реалистичную реалистичную реализацию BufferingSMTPHandler, которая отправляет электронные письма из отдельного потока. Основная цель - не блокировать основной поток.

Как написано, он использует две очереди - это казалось необходимым для реализации некоторых полезных параметров уровня класса, определенных в разделе "Конфигурируемые параметры" кода. Хотя вы можете использовать код как есть, вероятно, лучше, если вы изучите и используете его для написания своего собственного класса.

Вопросы:

  • Некоторые параметры уровня класса могут быть, возможно, на уровне экземпляра.
  • Либо threading.Timer, либо модуль signal можно было бы использовать, чтобы избежать циклов, которые выполняются вечно.

Ответ 3

Если вы используете django - здесь используется простой буферизатор, который будет использовать стандартные методы электронной почты django:

import logging

from django.conf import settings
from django.core.mail import EmailMessage


class DjangoBufferingSMTPHandler(logging.handlers.BufferingHandler):
    def __init__(self, capacity, toaddrs=None, subject=None):
        logging.handlers.BufferingHandler.__init__(self, capacity)

        if toaddrs:
            self.toaddrs = toaddrs
        else:
            # Send messages to site administrators by default
            self.toaddrs = zip(*settings.ADMINS)[-1]

        if subject:
            self.subject = subject
        else:
            self.subject = 'logging'

    def flush(self):
        if len(self.buffer) == 0:
            return

        try:
            msg = "\r\n".join(map(self.format, self.buffer))
            emsg = EmailMessage(self.subject, msg, to=self.toaddrs)
            emsg.send()
        except Exception:
            # handleError() will print exception info to stderr if logging.raiseExceptions is True
            self.handleError(record=None)
        self.buffer = []

В django settings.py вам необходимо настроить электронную почту и выполнить регистрацию следующим образом:

EMAIL_USE_TLS = True
EMAIL_PORT = 25  
EMAIL_HOST = ''  # example: 'smtp.yandex.ru'
EMAIL_HOST_USER = ''  # example: '[email protected]'
EMAIL_HOST_PASSWORD = ''
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = EMAIL_HOST_USER

LOGGING = {
    'handlers': {
        ...
        'mail_buffer': {
            'level': 'WARN',
            'capacity': 9999,
            'class': 'utils.logging.DjangoBufferingSMTPHandler',
            # optional: 
            # 'toaddrs': '[email protected]'
            # 'subject': 'log messages'
        }
    },
    ...
}

Ответ 4

Для этой цели я использую BufferingSMTPHandler, предложенный Винаем Саджипом, с одной незначительной настройкой: я установил длину буфера на что-то действительно большое (скажем, на 5000 записей журнала) и вручную называет метод flush обработчика каждые несколько секунд и после проверки интернет-совместимость.

# init
log_handler1 = BufferingSMTPHandler(
    'smtp.host.lala', "[email protected]", ['[email protected]'], 'Log event(s)',5000)
...
logger.addHandler(log_handler1)
...

# main code
...
if internet_connection_ok and seconds_since_last_flush>60:
    log_handler1.flush() # send buffered log records (if any)