代码之家  ›  专栏  ›  技术社区  ›  SpliFF

使用smtphandler对python日志记录存储器handler中的输出进行排序

  •  13
  • SpliFF  · 技术社区  · 16 年前

    我已经为smtphandler目标设置了日志模块memoryhandler来排队调试和错误消息。我想要的是当进程出错时发送一封电子邮件,其中包含到该点为止的所有调试语句(每行一个)。相反,我得到的是每个调试消息的单独电子邮件。

    这看起来应该是微不足道的,也是日志包的一部分,但是我找不到任何关于它的信息,没有例子,在谷歌上什么也找不到。

    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 反正? 应该 错误邮件处理程序 设置为调试或错误目标?当它被喂食时是否需要一个目标? 内存处理程序 ?

    希望看到任何解决了这个问题的人的一些工作代码。

    5 回复  |  直到 7 年前
        1
  •  24
  •   Vinay Sajip    13 年前

    您可能希望使用或调整 BufferingSMTPHandler 这是在 this test script .

    一般来说,如果一个已添加到记录器中的memoryhandler处理程序的目标是一个处理程序,则不需要向记录器中添加该处理程序。如果设置了处理程序的级别,这将影响处理程序实际处理的内容-它不会处理比其级别设置严重的任何内容。

        2
  •  5
  •   Asclepius    11 年前

    我编写了自己的线程安全实现 BufferingSMTPHandler 从一个单独的线程发送电子邮件。主要目标是不要阻塞主线程。

    如文所述,它使用两个队列——这似乎是实现一些在代码的“可配置参数”部分定义的有用的类级参数所必需的。虽然您可以按原样使用代码,但如果您学习并使用它编写自己的类,可能会更好。

    问题:

    • 一些类级参数可能是实例级的。
    • 要么 threading.Timer signal 模块可能被用来避免永远运行的循环。
        3
  •  2
  •   user920391    10 年前

    如果您使用的是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'
            }
        },
        ...
    }
    
        4
  •  0
  •   ndemou    14 年前

    为此,我使用 缓冲Mtphandler VinaySajip建议了一个小的调整:我将缓冲区长度设置为非常大的值(比如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)
    
        5
  •  0
  •   Ed McGuigan    7 年前

    我认为关于SMTP日志记录器的要点是,如果发送给人工收件人或由自动收件人进一步处理,它将发送一条重要的日志消息,作为某种警报。

    如果要通过电子邮件发送一组日志消息,那么在任务执行结束时发送一个报告,并将该日志写入文件,然后通过电子邮件发送该文件似乎是一个合理的解决方案。

    我查看了基本的文件处理程序日志处理程序,以及如何构建写入临时文件的机制,然后在脚本退出时附加该临时文件。

    我发现了“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")
    

    希望这能帮助别人。