详解python logging 模块发邮件

工作中需要及时解决线上的 bug,所以,及时获取 log 中的 warning,error 是非常有必要的,在查找资料的过程中发现了logging.handlers.SMTPHandler可以实现日志发送到邮件,通过简单的配置就可以使用,不必自己再烦心重写。

 

1、SMTPHandler默认情况下不支持SMTPS

import logging
import logging.handlers


def get_logger(logger_name, logger_level, logger_location, days):
    logger = logging.getLogger(logger_name)
    logger.setLevel(logger_level)
    
    log_format = "%(name)s\t%(asctime)s\t%(pathname)s\t[line:%(lineno)d]\t %(levelname)s\t %(message)s"
    formater = logging.Formatter(log_format)
    
    # 存入文件的日志
    handler = logging.handlers.TimedRotatingFileHandler(logger_location, "midnight", 1, days, encoding="utf-8")
    handler.suffix = "%Y%m%d"
    handler.setFormatter(formater)
    logger.addHandler(handler)

    # 发邮件的日志
    sh = logging.handlers.SMTPHandler("smtp.163.com", send_email, [receive_email_1, receive_email_2],
                    "log error", credentials=(send_email, authority_password),secure=())
    sh.setLevel(logging.ERROR)
    sh.setFormatter(formater)
    logger.addHandler(sh)
    
    return logger

注意:邮箱的密码不是登录密码,而是授权码。首先需要打开邮箱的客户端授权,然后设置授权码。

 

2、SMTPHandler支持SMTPS的方法:

 

def emit(self, record):
    """
    Overwrite the logging.handlers.SMTPHandler.emit function with SMTP_SSL.
    Emit a record.
    Format the record and send it to the specified addressees.
    """
    try:
        import smtplib
        from email.utils import formatdate
        port = self.mailport
        if not port:
            port = smtplib.SMTP_PORT
        smtp = smtplib.SMTP_SSL(self.mailhost, port, timeout=self._timeout)
        msg = self.format(record)
        msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (self.fromaddr, ", ".join(self.toaddrs), self.getSubject(record), formatdate(), msg)
        if self.username:
            smtp.ehlo()
            smtp.login(self.username, self.password)
        smtp.sendmail(self.fromaddr, self.toaddrs, msg)
        smtp.quit()
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        self.handleError(record)

然后设置

logging.handlers.SMTPHandler.emit = emit

 

 

3、防止邮箱爆炸

每一条错误日志都会对应一封邮件的发送,如果多条错误,邮箱且不是要爆掉。logging.handlers.MemoryHandler是将日志输出的内存中定制的buffer,一旦buffer存满或是超过设定的级别就会将日志记录发送给指定的target handler处理。

 

def flush(self):
    """
    For a MemoryHandler, flushing means just sending the buffered
    records to the target, if there is one. Override if you want
    different behaviour.
    """
    if self.target:
        for record in self.buffer:
            self.target.handle(record)
        self.buffer = []

从代码中可以看出,虽然我们暂时缓存了多条日志数据,但是当缓存溢出时,对应buffer中的每一条记录,都对应一个动作,即,如果我们设置target为SMTPHandler,还是会发送多个邮件。So, override if you want different behaviour。


 class OptmizedMemoryHandler(logging.handlers.MemoryHandler):
     def __init__(self, capacity, mail_subject, mail_host, mail_from, mail_to):
         """ capacity: flush memory
             mail_subject: warning mail subject
             mail_host: the email host used
             mail_from: address send from; str
             mail_to: address send to; multi-addresses splitted by ';'
 
         """
         logging.handlers.MemoryHandler.__init__(self, capacity, flushLevel = logging.ERROR,\
             target = None)
         self.mail_subject = mail_subject
         self.mail_host = mail_host
         self.mail_from = mail_from
         self.mail_to = mail_to
 
     def flush(self):
         """if flushed send mail
         """
         if self.buffer != [] and len(self.buffer) >= self.capacity:
             content = ''
             for record in self.buffer:
                 message = record.getMessage()
                 content += record.levelname + " occurred at " + time.strftime('%Y-%m-%d %H:%M:%S',time.localti    me(record.created)) + "  : " + message + '\n'
             self.send_warning_mail(self.mail_subject, content,self.mail_host, self.mail_from, self.mail_to)
             self.buffer = []
 
     def send_warning_mail(self, subject, content, host, from_addr, to_addr):
         """send mail
         """
         msg = MIMEText(content)
         msg['Subject'] = subject
         try:
             smtp = smtplib.SMTP()
             smtp.connect(host)
             smtp.sendmail(from_addr, to_addr, msg.as_string())
             smtp.close()
         except:
             print traceback.format_exc()
 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值