一、邮件操作包
mail_helper.py是邮件操作包,用来发送邮件的。
#!/usr/bin/evn python # coding=utf-8 import smtplib from email.mime.text import MIMEText from traceback import format_exc from config import const # 初始化邮件参数 smtp = const.SMTP port = const.PORT user = const.EMAIL_USER passwd = const.EMAIL_PWD email_list = const.EMAIL_LIST err_title = const.EMAIL_ERR_TITLE def send_mail(subject, context, to_list): ''' 发送邮件 接收参数: subject 邮件主题 context 邮件内容 to_list 接收者邮件列表,每个邮件地址用","分隔 ''' if not subject or not context or not to_list: return '邮件发送失败,邮件主题、内容与收件人邮件都是必填项' # 初始始化邮件相关参数 email = MIMEText(context, 'html', 'utf-8') email['To'] = to_list email['Subject'] = subject email['From'] = user # QQ邮箱改为ssl方式发送了 # s = smtplib.SMTP(smtp) s = smtplib.SMTP_SSL(smtp) try: s.login(user, passwd) s.sendmail(user, email_list, email.as_string()) s.close() return None except Exception as e: s.close() stacktrace = format_exc() return '邮件发送失败,出现异常:' + str(e.args) + stacktrace + '\n' def send_error_mail(context): ''' 发送邮件 接收参数: context 邮件内容 ''' if not context: return '邮件内容是必填项' send_mail(err_title, context, email_list)
send_mail()函数只需要提交邮件标题、内容和收件人列表,就可以将邮件发送出去,使用的发件人是前面配置const.py里设置的帐号,如果没有在配置里设置好对应的账号密码,邮件将会发送不成功。
send_error_mail()函数是用来发送异常日志信息的,它默认是给log_helper.py里的异常日志记录函数error()调用,这样当代码执行时出现异常,我们第一时间就会收到这封异常邮件,然后可以针对性的去进行处理。当然如果服务器出现故障时,有可能会一下子收到非常多的邮件,被邮件服务器封掉IP的。所以一般我都会用自己的邮箱给自己发,这样万一给封了IP还是可以收到发送不成功的邮件的。另外,前面说过,api文件夹里的__init__.py和其他文件夹的这个文件有点不一样,大家可以对比一下,它会帮我们解决很多很基本的问题,特别是更新线上代码时,有时会忘记提交新建的python文件,而这个文件又被其它文件所调用,这时python初始化就会发生异常,第一时间我们就会收到提醒邮件,避免线上服务挂了也不知道的情况发生。
send_error_mail()函数的邮件标题可以在const.py配置中进行设置(见下面参数),一般我会分开发、测试、预生产、生产等标题,这样在收到邮件时方便我们区分是那一个环境出现了故障
### 邮件服务参数 ### # 邮件服务器 SMTP = 'smtp.qq.com' # 邮件服务器端口 PORT = 465 # email发送账号 EMAIL_USER = 'xxxxxx@qq.com' # email发送密码 EMAIL_PWD = 'xxxxxxxxxxxxxxxxx' # 系统异常邮件通知地址,多个地址用逗号分隔 EMAIL_LIST = 'xxxxxx@qq.com' # 异常邮件通知标题 # ——由于我们有开发环境、测试环境、预生产环境、生产环境等多个不同的环境, # ——所以在发送异常通知时如果区分的话,可能就弄不清是那个环境出了问题, # ——我们可以通过设置邮件标题为:开发、测试、预生产、生产等标签来方便区分是那个环境发送的异常通知 EMAIL_ERR_TITLE = '系统异常通知-simple-开发'
测试用例:
#!/usr/bin/evn python # coding=utf-8 import unittest from common import mail_helper, except_helper class MailHelperTest(unittest.TestCase): """邮件操作包测试类""" def setUp(self): """初始化测试环境""" print('------ini------') def tearDown(self): """清理测试环境""" print('------clear------') def test(self): mail_helper.send_mail('test', 'test', '1654937@qq.com') except_info = except_helper.detailtrace() mail_helper.send_error_mail('出现异常,堆栈信息:' + except_info) if __name__ == '__main__': unittest.main()
执行结果
二、日志操作包
新建log_helper.py文件,代码如下:
#!/usr/bin/evn python # coding=utf-8 import logging import logging.handlers import traceback from common import mail_helper, except_helper def info(content): """记录日志信息""" if content: logging.info(content) def error(content = '', is_send_mail = True): """记录错误日志信息""" if traceback: content = content + '\n' + traceback.format_exc() + '\n' # 获取程序当前运行的堆栈信息 detailtrace = except_helper.detailtrace() content = content + '程序调用堆栈的日志:' + detailtrace + '\n' logging.info(content) # 发送邮件通知相关人员 if is_send_mail: info = mail_helper.send_error_mail(context=content) if info: logging.info(info)
log_helper.py是日志操作包,info()函数用于记录程序执行过程中的一些信息,比如与第三方接口(最常见的是支付接口)通讯时,将提交的网址、参数和返回的结果记录下来,方便我们在需要时查看,排查出错问题;比如我们需要排查生产环境异常,定位错误信息位置时,在相关代码中间添加,然后将相关数据变量值记录下来,帮助我们定位问题所在......
error()函数除了拥有info()函数的功能外,它在记录信息的同时,还会自动发送一封邮件到我们的邮箱。通过它放在try...except...中。
测试代码:
#!/usr/bin/evn python # coding=utf-8 import logging import os import unittest from common import log_helper class LogHelperTest(unittest.TestCase): """日志操作包测试类""" def setUp(self): """初始化测试环境""" print('------ini------') # 获取本脚本所在的上级路径(因为log_helper_text.py是在test目录下面,并不在根目录,而我们想将日志都记录在根据目录下的log目录里,所以需要获取test的上级目录) program_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) # 初始化日志目录 log_path = os.path.join(program_path, 'log') # 当日志目录不存在时创建日志目录 if not os.path.exists(log_path): os.mkdir(log_path) # 定义日志输出格式 logging.basicConfig(level=logging.INFO, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', filename="%s/info.log" % log_path, filemode='a') def tearDown(self): """清理测试环境""" print('------clear------') def test(self): log_helper.info('记录代码执行的相关记录或信息') try: result = '0' / 10 except Exception as e: log_helper.error('出现异常:' + str(e.args)) if __name__ == '__main__': unittest.main()
执行结果
三、随机数操作包
random_helper.py是随机数操作包,通过里面的函数,我们可以方便快捷的获取指定大小范围的数值型随机数;指定长度的数字、大小写字母、数字与字母混合型随机数;获取uuid随机码。
#!/usr/bin/evn python # coding=utf-8 import random import uuid from common import encrypt_helper ### 定义常量 ### # 小写字母 lowercase_letters = "abcdefghijklmnopqrstuvwxyz" # 大写字母 majuscule = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" # 数字 numbers = "0123456789" ################ def ___get_randoms(length, text): """ 内部函数,获取指定长度的随机字符 :param length: 将要生成的字符长度 :param text: 生成随机字符的字符池 :return: 生成好的随机字符串 """ return random.sample(text, length) def get_number(length): """ 获取指定长度的数字,类型是字符串 :param length: 将要生成的字符长度 :return: 生成好的随机字符串 """ return ''.join(___get_randoms(length, numbers)) def get_number_for_range(small, max): """ 获取指定大小的整形数值 :param small: 最小数值 :param max: 最大数值 :return: 生成好的随机数值 """ return random.randint(small, max) def get_string(length): """ 获取指定长度的字符串(大小写英文字母+数字) :param length: 将要生成的字符长度 :return: 生成好的随机字符串 """ return ''.join(___get_randoms(length, lowercase_letters + majuscule + numbers)) def get_letters(length): """ 生成随机英文字母字符串(大小写英文字母) :param length: 将要生成的字符长度 :return: 生成好的随机字符串 """ return ''.join(___get_randoms(length, lowercase_letters + majuscule)) def get_uuid(): """ 随机生成uuid :return: 生成好的uuid """ return str(uuid.uuid4()).replace('-', '')
测试代码:
#!/usr/bin/evn python # coding=utf-8 import unittest from common import random_helper class RandomHelperTest(unittest.TestCase): """随机数操作包测试类""" def setUp(self): """初始化测试环境""" print('------ini------') def tearDown(self): """清理测试环境""" print('------clear------') def test(self): print('获取0到100之间的随机数') print(random_helper.get_number_for_range(0, 100)) print(random_helper.get_number_for_range(0, 100)) print('获取长度为5的数字随机码') print(random_helper.get_number(5)) print(random_helper.get_number(5)) print('获取长度为6的英文随机码') print(random_helper.get_letters(6)) print(random_helper.get_letters(6)) print('获取长度为6的数字与英文随机码') print(random_helper.get_string(6)) print(random_helper.get_string(6)) print('获取uuid') print(random_helper.get_uuid()) print(random_helper.get_uuid()) if __name__ == '__main__': unittest.main()
测试结果:
------ini------ 获取0到100之间的随机数 21 获取长度为5的数字随机码 58132 获取长度为6的英文随机码 BqQCZP ybFIaB 获取长度为6的数字与英文随机码 FZfEgd GAslRy 获取uuid 2aba0e946414434ea6b7f2e425d8b41b 52fe4545b09443a088ce460453d909fa ------clear------