Разобрать выходные данные в журнале Python MemoryHandler с SMTPHandler - PullRequest
16 голосов
/ 23 октября 2009

У меня есть модуль регистрации 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, 'errors@'+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 быть установлено на цель ОТЛАДКА или ОШИБКА? Нужна ли ему цель, когда ее кормят с memory_handler?

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

Ответы [ 5 ]

26 голосов
/ 23 октября 2009

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

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

5 голосов
/ 01 декабря 2011

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

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

Вопросы:

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

Если вы используете 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: 'user@yandex.ru'
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': 'admin@host.com'
            # 'subject': 'log messages'
        }
    },
    ...
}
0 голосов
/ 30 октября 2018

Я думаю, что смысл в протоколе SMTP заключается в том, что он предназначен для отправки значимого сообщения журнала, функционирующего как своего рода предупреждение, если оно отправлено человеку-получателю или еще для дальнейшей обработки автоматическим получателем.

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

Я взглянул на базовый обработчик журнала FileHandler и на то, как создать механизм для записи во временный файл, а затем присоединить этот временный файл при выходе из сценария.

Я нашел модуль "atexit"это позволяет зарегистрировать метод, который будет выполняться для объекта при выходе из скрипта.

import logging
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
import os
from email import encoders
import uuid
# atexit allows for a method to be set to handle an object when the script             exits
import atexit
filename = uuid.uuid4().hex
class MailLogger:

def __init__(self, filePath, smtpDict):
    self.filePath = filePath
    self.smtpDict = smtpDict
    # Generate random file name
    filename = '%s.txt' % ( uuid.uuid4().hex )
    # Create full filename
    filename = '%s/%s' % (filePath,filename)
    self.filename = filename
    self.fileLogger = logging.getLogger('mailedLog')
    self.fileLogger.setLevel(logging.INFO)
    self.fileHandler = logging.FileHandler(filename)
    self.fileHandler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
    self.fileHandler.setFormatter(formatter)
    self.fileLogger.addHandler(self.fileHandler)
    atexit.register(self.mailOut)

def mailOut(self):
    '''
    Script is exiting so time to mail out the log file

    "emailSettings":    {
                        "smtpServer"    :     "smtp.dom.com",
                        "smtpPort"        :    25,
                        "sender"        :    "sender@dom.com>",
                        "recipients"    :    [
                                                "recipient@dom.com"
                                            ],
                        "subject"        :    "Email Subject"
},
    '''
    # Close the file handler
    smtpDict = self.smtpDict
    self.fileHandler.close()
    msg = MIMEMultipart('alternative')
    s = smtplib.SMTP(smtpDict["smtpServer"], smtpDict["smtpPort"] )        
    msg['Subject'] = smtpDict["subject"]
    msg['From'] = smtpDict["sender"]
    msg['To'] = ','.join(smtpDict["recipients"])
    body = 'See attached report file'    
    content = MIMEText(body, 'plain')
    msg.attach(content)
    attachment = MIMEBase('application', 'octet-stream')
    attachment.set_payload(open(self.filename, 'rb').read())
    encoders.encode_base64(attachment)
    attachment.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(self.filename))
    msg.attach(attachment)
    s.send_message(msg)
    s.quit()

Мой базовый тестовый скрипт:

from EmailLogRpt import MailLogger
import time
smtpDict = {
                        "smtpServer"    :     "smtp.dom.com",
                        "smtpPort"        :    25,
                        "sender"        :    "sender@dom.com",
                        "recipients"    :    [
                                                "recpient@dom.com>"
                                            ],
                        "subject"        :    "Email Subject"
}
myMailLogger = MailLogger("/home/ed/tmp",smtpDict).fileLogger
myMailLogger.info("test msg 1")
time.sleep(5)
myMailLogger.info("test msg 2")

Надеюсь, это кому-нибудь поможет.

0 голосов
/ 24 октября 2011

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

# init
log_handler1 = BufferingSMTPHandler(
    'smtp.host.lala', "from@test.com", ['to@test.com'], '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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...