Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Python发送带有输出日志和成功状态的电子邮件_Python_Python 3.x_Logging_Error Handling - Fatal编程技术网

用Python发送带有输出日志和成功状态的电子邮件

用Python发送带有输出日志和成功状态的电子邮件,python,python-3.x,logging,error-handling,Python,Python 3.x,Logging,Error Handling,我想在每次脚本运行后自动发送一封电子邮件,无论它是否成功。 电子邮件应包括日志,如果出现错误,还应包括堆栈跟踪。 主题应该包含一个后缀,告诉运行是有错误(“错误”)还是没有错误(“成功”) 目前,我正在使用以下代码,这是一个丑陋的方式: if __name__ == '__main__': # setup logging and e-mail messaging logger = logging.getLogger(__name__) # Creating an instanc

我想在每次脚本运行后自动发送一封电子邮件,无论它是否成功。 电子邮件应包括日志,如果出现错误,还应包括堆栈跟踪。 主题应该包含一个后缀,告诉运行是有错误(“错误”)还是没有错误(“成功”)

目前,我正在使用以下代码,这是一个丑陋的方式:

if __name__ == '__main__':
    # setup logging and e-mail messaging
    logger = logging.getLogger(__name__)  # Creating an instance of logger
    logger.setLevel(logging.DEBUG)
    mail_handler = BufferingSMTPHandler(fromaddr='xyz@test.de',
                                        toaddr=['xyz@tzest.de'],
                                        subject='JOB: Testjob')
    mail_handler.setLevel(logging.INFO)  # Set minimum level to receive messages
    logger.addHandler(mail_handler)
    # rest of __main__ is at the end of the file!


def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logger.critical("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
    mail_handler.set_failed(True)
    mail_handler.flush()

if __name__ == '__main__':
    .... do work here
    logger.info('TEST')
    ....
    mail_handler.set_failed(False)  # reached end of the script, so success is assumed
    mail_handler.flush()
BufferingSMTPHandler如下所示:

import logging
import logging.handlers
import smtplib


class BufferingSMTPHandler(logging.handlers.BufferingHandler):
    def __init__(self, subject, fromaddr, toaddr, mailhost='mysmtpserver', capacity=500):
        logging.handlers.BufferingHandler.__init__(self, capacity)
        self.mailhost = mailhost
        self.fromaddr = fromaddr
        self.toaddr = toaddr
        self.subject = subject
        self.failed = False

        self.setFormatter(logging.Formatter(
            '{levelname} - {asctime} - {lineno} - {name} -  In {funcName}: {message}',
            style='{'))  # Formatter to prettify logs

    def set_failed(self, failed):
        self.failed = failed

    def flush(self):  # Method to send emails
        if len(self.buffer) <= 0:
            return

        with smtplib.SMTP(self.mailhost) as smtp:
            if self.failed:
                subject = self.subject + ' - ERROR'
            else:
                subject = self.subject + ' - SUCCESS'
            body = ''

            for record in self.buffer:
                body += self.format(record) + '\n'  # Populating body of the message with formatted logs

            msg = f'Subject: {subject}\n\n{body}'

            smtp.sendmail(self.fromaddr, self.toaddr, msg)
            self.buffer.clear()  # Clearing buffer to allude sending same logs
from auto_status_mailer import AutoStatusMailer

auto_status_mailer = AutoStatusMailer(fromaddr='test@test.de',
                                      toaddr=['test@test.de', 'test2@test.de'],
                                      subject='JOB: My Job',
                                      mailhost='mri.server.lan')

logger = auto_status_mailer.get_logger()

logger.info("Test")
# raise ValueError("TEST")

我根据StackOverflow上的信息创建了一个名为AutoStatusMailer的类来解决这个问题:

import atexit
import collections
import logging
import smtplib
import sys
from email.message import EmailMessage


class TailLogHandler(logging.Handler):
    def __init__(self, log_queue, formatter=None):
        logging.Handler.__init__(self)
        self.log_queue = log_queue
        if not formatter:
            formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        self.setFormatter(formatter)

    def emit(self, record):
        self.log_queue.append(self.format(record))


class TailLogger(object):
    def __init__(self, maxlen, formatter=None):
        self._log_queue = collections.deque(maxlen=maxlen)
        self._log_handler = TailLogHandler(self._log_queue, formatter)

    def contents(self):
        return '\n'.join(self._log_queue)

    @property
    def log_handler(self):
        return self._log_handler


class AutoStatusMailer:
    def __init__(self, fromaddr, toaddr, subject, mailhost, log_length=500, log_level=logging.DEBUG, log_console=True,
                 call_original_excepthook_on_error=False):
        self.mailhost = mailhost
        self.fromaddr = fromaddr
        self.toaddr = toaddr
        self.subject = subject
        self.failed = False
        self.call_original_excepthook_on_error = call_original_excepthook_on_error

        self.logger = logging.getLogger('auto_status_mail_logger')  # Creating an instance of logger
        self.logger.setLevel(log_level)

        if log_console:
            console_handler = logging.StreamHandler(sys.stdout)
            console_handler.setLevel(log_level)
            self.logger.addHandler(console_handler)

        self.tail = TailLogger(log_length)
        tail_handler = self.tail.log_handler
        tail_handler.setLevel(log_level)  # Set minimum level to receive messages
        self.logger.addHandler(tail_handler)

        self.original_excepthook = sys.excepthook
        sys.excepthook = self.handle_exception
        atexit.register(self.send_mail)

    def get_logger(self):
        return self.logger

    def handle_exception(self, exc_type, exc_value, exc_traceback):
        if issubclass(exc_type, KeyboardInterrupt):
            sys.__excepthook__(exc_type, exc_value, exc_traceback)
            return

        self.logger.critical("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
        self.failed = True

        if self.call_original_excepthook_on_error:
            self.original_excepthook(exc_type, exc_value, exc_traceback)

    def send_mail(self):
        with smtplib.SMTP(self.mailhost) as smtp:
            if self.failed:
                subject = self.subject + ' - ERROR'
            else:
                subject = self.subject + ' - SUCCESS'
            msg = EmailMessage()
            msg.set_content(self.tail.contents())
            msg['Subject'] = subject
            msg['From'] = self.fromaddr
            msg['To'] = ', '.join(self.toaddr)
            smtp.send_message(msg)
它是这样使用的:

import logging
import logging.handlers
import smtplib


class BufferingSMTPHandler(logging.handlers.BufferingHandler):
    def __init__(self, subject, fromaddr, toaddr, mailhost='mysmtpserver', capacity=500):
        logging.handlers.BufferingHandler.__init__(self, capacity)
        self.mailhost = mailhost
        self.fromaddr = fromaddr
        self.toaddr = toaddr
        self.subject = subject
        self.failed = False

        self.setFormatter(logging.Formatter(
            '{levelname} - {asctime} - {lineno} - {name} -  In {funcName}: {message}',
            style='{'))  # Formatter to prettify logs

    def set_failed(self, failed):
        self.failed = failed

    def flush(self):  # Method to send emails
        if len(self.buffer) <= 0:
            return

        with smtplib.SMTP(self.mailhost) as smtp:
            if self.failed:
                subject = self.subject + ' - ERROR'
            else:
                subject = self.subject + ' - SUCCESS'
            body = ''

            for record in self.buffer:
                body += self.format(record) + '\n'  # Populating body of the message with formatted logs

            msg = f'Subject: {subject}\n\n{body}'

            smtp.sendmail(self.fromaddr, self.toaddr, msg)
            self.buffer.clear()  # Clearing buffer to allude sending same logs
from auto_status_mailer import AutoStatusMailer

auto_status_mailer = AutoStatusMailer(fromaddr='test@test.de',
                                      toaddr=['test@test.de', 'test2@test.de'],
                                      subject='JOB: My Job',
                                      mailhost='mri.server.lan')

logger = auto_status_mailer.get_logger()

logger.info("Test")
# raise ValueError("TEST")

您知道pythons日志已经有了一个SMTPHandler吗?但是,处理程序不是为每个日志条目发送电子邮件吗?我想把日志作为一封邮件发送。此外,我希望主题根据是否引发异常而有所不同。我目前正在研究一些可能解决该问题的方法,如果有效,我会将其作为答案发布在这里