3分钟通过日志定位bug,这个技能测试人必须会
♥ 前 言
软件开发中通过日志记录程序的运行情况是一个开发的好习惯,对于错误排查和系统运维都有很大帮助。
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') 
 
2. 日志级别
根据不同情况设置了五种日志等级,不同情况输出不同等级的日志。
|   日志等级 (level)  |   描述  | 
|   DEBUG  |   调试信息,通常在诊断问题的时候用得着  | 
|   INFO  |   普通信息,确认程序按照预期运行  | 
|   WARNING  |   警告信息,表示发生意想不到的事情,或者指示接下来可能会出现一些问题,但是程序还是继续运行  | 
|   ERROR  |   错误信息,程序运行中出现了一些问题,程序某些功能不能执行  | 
|   CRITICAL  |   危险信息,一个严重的错误,导致程序无法继续运行  | 
日志器设置的级别会过滤掉低于这个级别的日志
import logging
logging.basicConfig(level=logging.WARNING,  #设置级别,根据等级显示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') 
3. 配置
basicConfig 方法支持一下关键字参数进行配置。
|   参数  |   描述  | 
|   filename  |   使用指定的文件名而不是 StreamHandler 创建 FileHandler。  | 
|   filemode  |   如果指定了 filename,则用此 模式 打开该文件。默认模式为 'a'。  | 
|   format  |   处理器使用的指定格式字符串。  | 
|   datefmt  |   使用指定的日期/时间格式,与 time.strftime() 所接受的格式相同。  | 
|   style  |   如果指定了 format,将为格式字符串使用此风格。'%', '{' 或 '$' 分别对应于 printf 风格,str.format() 或 string.Template。默认为 '%'。  | 
|   level  |   设置根记录器级别去指定 level。  | 
|   stream  |   使用指定的流初始化 StreamHandler。请注意此参数与 filename 是不兼容的 - 如果两者同时存在,则会引发 ValueError。  | 
|   handlers  |   如果指定,这应为一个包含要加入根日志记录器的已创建处理程序的可迭代对象。任何尚未设置格式描述符的处理程序将被设置为在此函数中创建的默认格式描述符。请注意此参数与 filename 或 stream 不兼容 —— 如果两者同时存在,则会引发 ValueError。  | 
|   force  |   如果将此关键字参数指定为 true,则在执行其他参数指定的配置之前,将移除并关闭附加到根记录器的所有现有处理器。  | 
4. 格式化规则
日志的输出格式可以通过下面格式自由组合输出
|   规则  |   描述  | 
|   %(asctime)s  |   日志事件发生的时间  | 
|   %(levelname)s  |   该日志记录的日志级别  | 
|   %(message)s  |   日志记录的文本内容  | 
|   %(name)s  |   所使用的日志器名称,默认是'root'  | 
|   %(pathname)s  |   调用日志记录函数的文件的全路径  | 
|   %(filename)s  |   调用日志记录函数的文件  | 
|   %(module)s  |   模块 (filename 的名称部分)。  | 
|   %(funcName)s  |   调用日志记录函数的函数名  | 
|   %(lineno)d  |   调用日志记录函数的代码所在的行号  | 
常用格式:%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:% (message)s
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') 
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') 
 
注意,配置了 fielname 后,日志将不会输出在控制台。
二、高级用法
简单的代码通过 logging 直接使用即可,如果要深入使用需要按照面向对象的方式使用 logging。
1. 日志组件
logging 模块包含一下几个组件。
|   组件  |   说明  | 
|   Loggers(日志记录器)  |   提供程序直接使用的接口  | 
|   Handlers(日志处理器)  |   将记录的日志发送到指定的位置  | 
|   Filters(日志过滤器)  |   用于过滤特定的日志记录  | 
|   Formatters(日志格式器)  |   用于控制日志信息的输出格式  | 
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='py34.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 支持根据时间进行轮转日志文件
 
更多详情见官方文档
(https://docs.python.org/zh-cn/3/library/logging.handlers.html?utm_source=testingpai.com#module-logging.handlers)
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 创建过滤器
过滤器用来过滤指定日志。具体使用略,一般用不到。
详情见官方文档
(https://docs.python.org/zh-cn/3/howto/logging-cookbook.html?utm_source=testingpai.com#filters-contextual)
2.5 将处理器添加到记录器上
logger.addHandler(file_handler)
logger.addHandler(console_handler) 
 
2.6 记录日志
logger.info('This is a info') 
 
logger.warning('This is a warning') 
 
三、日志模块封装
1. 功能分析
- 能够自定义日志器名
 - 能够自定义日志文件名和路径
 - 能够自定义日志文件编码方式
 - 能够自定义日志格式
 - 使用时间轮转处理器,并能够配置
 
2.封装成函数
在 common 目录下创建模块 log_handler.py 在其中创建如下函数。
import logging
from logging.handlers import TimedRotatingFileHandlerdef 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.DEBUGconsole_level = logging.DEBUGelse:file_level = logging.WARNINGconsole_level = logging.INFOif 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 loggerif __name__ == '__main__':log = get_logger(name='py41', filename='py41.log', debug=True, when='s')log.info('我是普通信息')import timetime.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 eelse:logger.info('测试用例【{}】断言成功'.format(case['title']))finally:logger.info('测试用例【{}】测试结束') 
相关文章:
3分钟通过日志定位bug,这个技能测试人必须会
♥ 前 言 软件开发中通过日志记录程序的运行情况是一个开发的好习惯,对于错误排查和系统运维都有很大帮助。 Python 标准库自带了强大的 logging 日志模块,在各种 python 模块中得到广泛应用。 一、简单使用 1. 入门小案例 import logging logging.ba…...
【论文总结】V-Shuttle:可扩展和语义感知的 Hypervisor 虚拟设备模糊测试
介绍 这是来自2021 CCS的一篇论文,作者有GaoningPan, Xingwei Lin, Xuhong Zhang, Yongkang Jia, Shouling Ji, Chunming Wu, Xinlei Ying, Jiashui Wang, Yanjun Wu。该论文提出V-shuttle的新框架来执行管控程序的模糊测试,该框架执行可扩展和语义感知…...
一篇文章让你搞懂TypeScript中的typeof()、keyof()是什么意思
TypeScript中的typeof()、keyof()是什么意思? 知识回调(不懂就看这儿!)场景复现核心干货👇👇👇举例引入字面量类型(literal types&…...
【机会约束、鲁棒优化】机会约束和鲁棒优化研究优化【ccDCOPF】研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
4月想跳槽的同学,没有更好的选择,可以去美团
在美团干了半年,说一下自己的感受,美团是一家福利中等,工资待遇中上,高层管理团队强大,加班强度一般,技术不错,办公环境一般,工作氛围中上,部门差距之间工作体验差距巨大…...
从输入url到页面展现(一)从浏览器解析url开始
前端面试有一道很考验人的问题,那就是:请你说一下从用户从输入url到页面展现的过程是怎样的?在接下来的一段时间呢,狗哥会从这一问题出发,开始剖析这个过程,希望可以让更多的小伙伴掌握到这个过程ÿ…...
购物 · 礼物
标题 前言必学场景词汇及用法书店花店玩具店讨价还价情境常用单词书店花店玩具店前言 加油 必学场景词汇及用法 书店 1.book store / book shop 书店 I browsed through the book store, but I didn’t find the book I was looking for. 我把书店里的书浏览了一番,但是没…...
可视化图表API格式要求有哪些?Sugar BI详细代码示例(2)
Sugar BI中的每个图表可以对应一个数据 API,用户浏览报表时,选定一定的过滤条件,点击「查询」按钮将会通过 API 拉取相应的数据;前面说过,为了确保用户数据的安全性,Sugar BI上的所有数据请求都在Sugar BI的…...
153. 寻找旋转排序数组中的最小值
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums [0,1,2,4,5,6,7] 在变化后可能得到: 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2] 若旋转 7 次࿰…...
Linux 文件描述符
Linux 文件描述符 Linux 中一切皆文件,比如 C 源文件、视频文件、Shell脚本、可执行文件等,就连键盘、显示器、鼠标等硬件设备也都是文件。 一个 Linux 进程可以打开成百上千个文件,为了表示和区分已经打开的文件,Linux 会给每个…...
第17章_反射机制
第17章_反射机制 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 1. 反射(Reflection)的概念 1.1 反射的出现背景 Java程序中,所有的对象都有两种类型:编…...
使用VBA小程序提高资产清查效率
资产清查是一件相当烦人的工作,去年使用LayUIPHPMS SQL Server 2014写了一个资产清查的程序,可惜写完了,LayUI已经停止更新了,就没有再完善下去,数据也没有更新,等于就废了。 今年又要进行资产清查…...
JavaSE学习进阶day07_02 异常
第三章 异常 3.1 异常概念 异常,就是不正常的意思。在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.在程序中的意思就是: 异常 :指的是程序在执行过程中,出现的非正常的情况࿰…...
操作系统学习笔记
文章目录 操作系统虚拟内存锁缓存机制CPU性能指标进程、线程文件管理系统 操作系统 操作系统是控制应用程序的执行,并充当应用程序和计算机硬件之间的接口。在计算机系统中,处于最外层的是(应用软件) 。 面向用户的就是外层的&am…...
【Spring Boot】SpringBoot设计了哪些可拓展的机制?
文章目录 前言SpringBoot核心源码拓展Initializer拓展监听器ApplicationListenerBeanFactory的后置处理器 & Bean的后置处理器AOP其他的拓展点 前言 当我们引入注册中心的依赖,比如nacos的时候,当我们启动springboot,这个服务就会根据配置…...
《程序员面试金典(第6版)》面试题 10.10. 数字流的秩
题目描述 假设你正在读取一串整数。每隔一段时间,你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。请实现数据结构和算法来支持这些操作,也就是说: 实现 track(int x) 方法,每读入一个数字都会调用该方法; 实现 g…...
智能洗地机好用吗?值得入手的洗地机推荐
洗地机是一款高效的地面清洁设备,不仅可以很好清理地面不同形态的干湿垃圾,还减少了人工和水资源的浪费,是我们日常生活中必不可少的清洁工具。作为以一位评测博主,很多朋友咨询我在选购洗地机时应该注意哪些要点,有哪…...
Spring Security实战(一)——基于内存和数据库模型的认证与授权
目录 简介 一、初识Spring Security(入门案例) (1)新建project (2)选择依赖 (3)编写一个 HelloController (4)启动项目,访问localhost:8080…...
轻松掌握FFmpeg编程:从架构到实践
轻松掌握FFmpeg编程:从架构到实践 (Master FFmpeg Programming with Ease: From Architecture to Practice 引言 (Introduction)FFmpeg简介与应用场景 (Brief Introduction and Application Scenarios of FFmpeg)为什么选择FFmpeg进行音视频处理 (Why Choose FFmpeg…...
桌面应用程序开发攻略(初步了解)
什么是桌面应用程序? 桌面应用开发是指为桌面计算机或其他类似设备(如服务器)开发软件应用程序的过程。桌面应用通常是独立于浏览器运行的,并且可以在操作系统的桌面或应用程序菜单中找到。桌面应用可以使用各种编程语言开发&…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
