python 日志模块的使用
日志
软件开发中通过日志记录程序的运行情况是一个开发的好习惯,对于错误排查和系统运维都有很大帮助。
python标准库自带了强大的 logging 日志模块,在各种python模块中得到广泛应用。
一、简单实用
1. 入门小案例
import logging logging.basicConfig(level=logging.DEBUG, # 设置级别,根据等级显示 format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s')#设置输出格式 logging.debug('This is a debug log') logging.info('This is a info log') logging.warning('This is a warning log') logging.error('This is a error log') logging.critical('This is a critical log') 2021-11-15 12:03:34,790-[3279673026.py-->line:4]-DEBUG:This is a debug log 2021-11-15 12:03:34,791-[3279673026.py-->line:5]-INFO:This is a info log 2021-11-15 12:03:34,792-[3279673026.py-->line:6]-WARNING:This is a warning log 2021-11-15 12:03:34,792-[3279673026.py-->line:7]-ERROR:This is a error log 2021-11-15 12:03:34,794-[3279673026.py-->line:8]-CRITICAL:This is a critical log
直接导入logging就可以直接调用各种级别的日志方法。
2. 日志级别
根据不同情况设置了五种日志等级,不同情况输出不同等级的日志。
日志器设置的级别会过滤掉低于这个级别的日志
import logging logging.basicConfig(level=logging.ERROR, # 设置级别,根据等级显示 format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s')#设置输出格式 logging.debug('This is a debug log') logging.info('This is a info log') logging.warning('This is a warning log') logging.error('This is a error log') logging.critical('This is a critical log') 2021-11-15 13:50:16,235-[4267381777.py-->line:4]-ERROR:This is a error log 2021-11-15 13:50:16,237-[4267381777.py-->line:5]-CRITICAL:This is a critical log
basicConfig方法支持以下关键字参数进行配置
4. 格式化规则
日志的输出格式可以通过下面格式自由组合输出
5. 日志写到文件
只需要配置filename参数即可
import logging logging.basicConfig(level=logging.WARNING, # 设置级别,根据等级显示 filename='example.log', format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s')# 设置输出格式 logging.debug('This is a debug log') logging.info('This is a info log') logging.warning('This is a warning log') logging.error('This is a error log') logging.critical('This is a critical log')
注意,配置filename后,日志将不会输出在控制台。
二、 高级用法
简单的代码通过logging直接使用即可,如果要深入使用需要按照面向对象的方式使用logging。
1. 日志组件
logging模块包含以下几个组件。
2. 步骤
2.1 创建日志记录器
import logging
第一步创建一个logger,用来产生日志
logger = logging.getLogger('%s_log'%name) logger.setLevel(logging.DEBUG) # 设置日志等级通过getLogger这个方法可以创建一个日志记录器,注意要给名字否则返回根日志记录器。
通过setLevel设置日志记录器的等级。
2.2 创建日志处理器
创建一个文本处理器用来将日志写入到文件
file_handler = logging.FileHandler(filename='py45.log',encoding='utf-8')file_handler.setLevel('WARNING') # 设置处理器的日志等级 # 创建一个控制台处理器用来将日志输出到控制台 console_handler = logging.StreamHandler() console_handler.setLevel('INFO') # 设置控制台处理器的日志等级日志处理器就是将日志发送到指定的位置。
FileHandler 将日志发送到文件 StreaHandler 将它可将日志记录输出发送到数据流例如 sys.stdout, sys.stderr 或任何文件类对象默认 sys.stdout 即控制台。 RotatingFileHandler 支持根据日志文件大小进行轮转 TimedRotatingFileHandler 支持根据时间进行轮转日志文件
2.3 创建格式化器
formatter = logging.Formatter(fmt='%(levelname)s %(asctime)s [%(filename)s-->line:%(lineno)d]:%(message)s')格式化器需要设置到处理器上 file_handler.setFormatter(formatter) console_handler.setFormatter(formatter)
2.4 创建过滤器
过滤器用来过滤指定日志。具体使用略,一般用不到。
2.5 将处理器添加到记录器上
logger.addHandler(file_handler)
logger.addHandler(console_handler)
2.6 记录日志
logger.info('This is a info') 2020-09-11 22:22:44,095-[-->line:1]-INFO:This is a info logger.warning('This is a warning') 2020-09-11 22:23:20,337-[-->line:1]-WARNING:This is a warning
三、日志模块封装
1. 功能分析
- 能够自定义日志器名
- 能够自定义日志文件名和路径
- 能够自定义日志文件编码方式
- 能够自定义日志格式
- 使用时间轮转处理器,并能够配置
2.封装成函数
在 common 目录下创建模块 log_handler.py 在其中创建如下函数。
import logging from logging.handlers import TimedRotatingFileHandler def get_logger(name, filename, encoding='utf-8', fmt=None, when='d', interval=1, backup_count=7, debug=False): """ :param name: 日志器的名字 :param filename: 日志文件名(包含路径) :param encoding: 字符编码 :param fmt: 日志格式 :param when: 日志轮转时间单位 :param interval: 间隔 :param backup_count: 日志文件个数 :param debug: 调试模式 :return: """ logger = logging.getLogger(name) logger.setLevel(logging.DEBUG)
文件处理器的等级一般情况一定比控制台要高
if debug: file_level = logging.DEBUG console_level = logging.DEBUG else: file_level = logging.WARNING console_level = logging.INFO if fmt is None: fmt = '%(levelname)s %(asctime)s [%(filename)s-->line:%(lineno)d]:%(message)s' file_handler = TimedRotatingFileHandler( filename=filename, when=when, interval=interval, backupCount=backup_count, encoding=encoding) file_handler.setLevel(file_level) console_handler = logging.StreamHandler() console_handler.setLevel(console_level) formatter = logging.Formatter(fmt=fmt) file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(console_handler) return logger if name == 'main': log = get_logger(name='py41', filename='py41.log', debug=True, when='s') log.info('我是普通信息') import time time.sleep(3) log.warning('我是警告信息')
四、应用到项目中
1. 导入
日志器生成函数的导入不能像 Excel 数据读取函数一样,每个用例模块里都导入一遍。因为它返回一个日志器对象,当多次调用日志器生成函数,且日志器名称相同时,会给同一个日志器添加多个日志处理器,从而出现重复记录日志器的问题。
为了解决上面的问题,在 common 文件夹下创建一个名为 init.py 的文件,在 common 模块被导入时会自动执行这个文件里的代码,且只会执行一次。
在 init.py 文件编写如下代码:
from .log_handler import get_logger logger = get_logger('py41', 'py38.log')那么在项目中的其他模块中就可以通过如下代码导入 from common import logger 从而可以保证在项目执行过程中,get_logger 方法只会执行一遍。
2. 记录日志
日志的作用是记录程序的运行状态和当程序出现问题时能提供定位分析错误的依据。
什么时候需要记录日志,记录什么日志,根据每个人对程序的理解,以及经验。
我们的项目中,在用例执行的过程是核心,所以我们的日志也是围绕着用例的执行。
使用日志记录每个用例的测试数据,和测试结果,代码如下:
... @list_data(*cases) def test_login(self, case): """ 登陆测试 """ logger.info('测试用例【{}】开始测试'.format(case['title']))
1. 测试数据
传入进来的 case 参数
logger.info('测试用例【{}】的测试数据是:{}'.format(case['title'], case))
2. 测试步骤
res = login_check(case['username'], case['password']) logger.info('测试用例【{}】的测试结果是:{}'.format(case['title'], res))
3. 断言
try: self.assertEqual(res, case['expect']) except AssertionError as e: logger.error('测试用例【{}】断言失败'.format(case['title'])) raise e else: logger.info('测试用例【{}】断言成功'.format(case['title'])) finally: logger.info('测试用例【{}】测试结束')