如何理解python接口自动化之logging日志模块


Posted in Python onJune 15, 2021

一、logging模块介绍

​前言:我们之前运行代码时都是将日志直接输出到控制台,而实际项目中常常需要把日志存储到文件,便于查阅,如运行时间、描述信息以及错误或者异常发生时候的特定上下文信息。

​Python中自带的logging模块提供了标准的日志接口,在debug时使用往往会事半功倍。为什么不直接使用print去输出呢?这种方式对简单的脚本来说有用,对于复杂的系统来说相当于一个花瓶摆设,大量的print输出很容易被遗忘在代码里,并且print是标准输出,这很难从一堆信息里去判断哪些是你需要重点关注的。

​logging的优势就在于可以控制日志的级别,把不需要的信息进行过滤,且可以决定它输出到什么地方、如何输出,还可以通过控制等级把特定等级的信息输出到特定的位置等。logging一共分为四个部分:

  • Loggers:日志收集器,可供程序直接调用的接口,app通过调用提供的api来记录日志
  • Handlers:日志处理器, 决定将日志记录分配至正确的目的地
  • Filters:日志过滤器,对日志信息进行过滤, 提供更细粒度的日志是否输出的判断
  • Formatters:日志格式器,制定最终记录打印的格式布局

二、日志等级

​logging将logger的等级划分成5个level,由低到高分别是DEBUG、INFO、WARNING、ERROE、CRITICAL,默认是WARNING级别,CRITICAL最高,相关等级说明如下:

Level 说明
DEBUG 输出详细的运行信息,主要用于调试,追踪问题时使用
INFO 输出正常的运行的信息,一切按预期进行的情况
WARNING 一些意想不到的或即将会发生的情况,比如警告:内存空间不足,但不影响程序运行
ERROR 由于某些问题,程序的一些功能会受到影响,还可以继续运行
CRITICAL 一个严重的错误,表明程序本身可能无法继续运行

​这些等级的日志中低包含高,比如INFO,会收集INFO及以上等级的日志,DEBUG等级的日志将不进行收集。下面我们来输出这5个等级的日志:

import logging

"""
logging模块默认收集的日志是warning以上等级的

"""

a = 100
logging.debug(a)
logging.info('这是INFO等级的信息')
logging.warning('这是WARNING等级的信息')
logging.error('这是ERROR等级的信息')
logging.critical('这是CRITICAL等级的信息')

​输出结果:

C:\software\python\python.exe D:/learn/test.py

WARNING:root:这是WARNING等级的信息

ERROR:root:这是ERROR等级的信息

CRITICAL:root:这是CRITICAL等级的信息

Process finished with exit code 0

三、日志收集器

​日志是怎么被收集和输出的呢?答案就是日志收集器,设置一个收集器,把指等级的日志信息输出到指定的地方,控制台或文件等,其工作过程大致如下:

如何理解python接口自动化之logging日志模块

​logging中默认的日志收集器是root,收集等级默认是WARNING,我们可以通过setLevel来改变它的收集等级。

# 获取默认的日志收集器root
my_log = logging.getLogger()
# 设置默认的日志收集器等级
my_log.setLevel("DEBUG")  # 日志将全部被收集

a = 100
logging.debug(a)
logging.info('这是INFO等级的信息')
logging.warning('这是WARNING等级的信息')
logging.error('这是ERROR等级的信息')
logging.critical('这是CRITICAL等级的信息')

​输出结果:

C:\software\python\python.exe D:/learn/test.py

DEBUG:root:100

INFO:root:这是INFO等级的信息

WARNING:root:这是WARNING等级的信息

ERROR:root:这是ERROR等级的信息

CRITICAL:root:这是CRITICAL等级的信息

 

Process finished with exit code 0

 

​除了使用默认的日志收集器,我们也可以自己创建一个收集器logging.getLogger,如下:

import logging

my_logger = logging.getLogger('my_logger')	# 创建logging对象
my_logger.setLevel('INFO')	# 设置日志收集等级

a = 100
logging.debug(a)
logging.info('这是INFO等级的信息')
logging.warning('这是WARNING等级的信息')
logging.error('这是ERROR等级的信息')
logging.critical('这是CRITICAL等级的信息')

​输出结果:

C:\software\python\python.exe D:/learn/test.py

WARNING:root:这是WARNING等级的信息

ERROR:root:这是ERROR等级的信息

CRITICAL:root:这是CRITICAL等级的信息

 

Process finished with exit code 0

四、日志处理器

​上面例子中设置的收集器都是输出到控制台,除此我们还可以输出到文件中。

​Handlers(处理器)的作用就是将logger发过来的信息进行准确地分配,送往正确的地方。比如,送往控制台、文件或者是两者。它决定了每个日志收集器的行为,是创建收集器之后需要配置的重点区域。每个Handler同样有一个日志级别,一个logger可以拥有多个handler也就是说logger可以根据不同的日志级别将日志传递给不同的handler。当然也可以相同的级别传递给多个handler,这就根据需求来灵活的配置了。

​下面实例中设置了两个handler,一个是输出到控制台,一个是输出到文件中。关键代码:

  • logging.StreamHandler:输出到控制台的处理器
  • logging.FileHandler:输出到文件的处理器
  • addHandler:添加处理器
  • removeHandler:移除处理器
import logging

my_logger = logging.getLogger('my_logger')
my_logger.setLevel('INFO')

# 创建一个输出到控制台的处理器
sh = logging.StreamHandler()
sh.setLevel("ERROR")    # 设置处理器的输出等级
my_logger.addHandler(sh)    # 将处理器绑定到日志收集器上

# 创建一个输出到文件的处理器
fh = logging.FileHandler("logs.logs", encoding="utf8")
fh.setLevel("INFO")
my_logger.addHandler(fh)
# my_logger.removeHandler(fh)	# 移除处理器

a = 100
my_logger.debug(a)
my_logger.info('这是INFO等级的信息')
my_logger.warning('这是WARNING等级的信息')
my_logger.error('这是ERROR等级的信息')
my_logger.critical('这是CRITICAL等级的信息')

运行结果:

C:\software\python\python.exe D:/learn/test.py

这是ERROR等级的信息

这是CRITICAL等级的信息

 

Process finished with exit code 0

如何理解python接口自动化之logging日志模块

五、日志过滤器

​Filters可以实现比level更复杂的过滤功能,限制只有满足过滤规则的日志才会被输出。比如我们定义了filter = logging.Filter('A.B'),并将这个Filter添加到了一个Handler上,则使用该Handler的Logger中只有名字带A.B前缀的Logger才能输出其日志。下面是一个简单实例:

import logging

# 这是logger1
my_logger = logging.getLogger('A.C,B')
my_logger.setLevel('INFO')

# 这是logger2
my_logger2 = logging.getLogger('A.B')
my_logger2.setLevel('INFO')

# 创建一个处理器,两个logger都使用这个处理器
sh = logging.StreamHandler()
sh.setLevel("ERROR")
my_logger.addHandler(sh)
my_logger2.addHandler(sh)

# 创建一个过滤器绑到处理器上
my_filter = logging.Filter(name='A.B')
sh.addFilter(my_filter)    # 把过滤器添加到处理器上
# sh2.removeFilter(my_filter)   # 移除过滤器

my_logger.debug('这是logger1-DEBUG等级的信息')
my_logger.info('这是logger1-INFO等级的信息')
my_logger.warning('这是logger1-WARNING等级的信息')
my_logger.error('这是logger1-ERROR等级的信息')
my_logger.critical('这是logger1-CRITICAL等级的信息')

my_logger2.debug('这是logger2-DEBUG等级的信息')
my_logger2.info('这是logger2-INFO等级的信息')
my_logger2.warning('这是logger2-WARNING等级的信息')
my_logger2.error('这是logger2-ERROR等级的信息')
my_logger2.critical('这是logger2-CRITICAL等级的信息')

​因为只有logger2满足过滤器的条件,因此只会输出logger2的日志,运行结果如下:

C:\software\python\python.exe D:/learn/test.py

这是logger2-ERROR等级的信息

这是logger2-CRITICAL等级的信息

 

Process finished with exit code 0

​filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,非0表示可以通过过滤。

六、日志格式器

​顾名思义,对日志进行格式化,因为常规的日志输出并不直观美观,通过美化日志的输出格式,可以让我们阅读起来更加舒服。

​format常用格式如下:

  • %(name)s: 打印收集器名称
  • %(levelno)s: 打印日志级别的数值
  • %(levelname)s: 打印日志级别名称
  • %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
  • %(filename)s: 打印当前执行程序名
  • %(funcName)s: 打印日志的当前函数
  • %(lineno)d: 打印日志的当前行号
  • %(asctime)s: 打印日志的时间
  • %(thread)d: 打印线程ID
  • %(threadName)s: 打印线程名称
  • %(process)d: 打印进程ID
  • %(message)s: 打印日志信息
import logging

my_logger = logging.getLogger('A.C,B')
my_logger.setLevel('INFO')

# 创建一个处理器
sh = logging.StreamHandler()
sh.setLevel("ERROR")
my_logger.addHandler(sh)
# 设置一个格式,并设置到处理器上
formatter = logging.Formatter('%(asctime)s - [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s')
sh.setFormatter(formatter)

my_logger.debug('这是logger1-DEBUG等级的信息')
my_logger.info('这是logger1-INFO等级的信息')
my_logger.warning('这是logger1-WARNING等级的信息')
my_logger.error('这是logger1-ERROR等级的信息')
my_logger.critical('这是logger1-CRITICAL等级的信息')

​运行结果:

C:\software\python\python.exe D:/learn/test.py

2020-08-01 18:28:43,645 - [test.py-->line:17] - ERROR: 这是logger1-ERROR等级的信息

2020-08-01 18:28:43,645 - [test.py-->line:18] - CRITICAL: 这是logger1-CRITICAL等级的信息

 

Process finished with exit code 0

 

七、日志滚动

​如果你用 FileHandler 存储日志,文件的大小会随着时间推移而不断增大,最终有一天它会占满你所有的磁盘空间。Python 的 logging 模块提供了两个支持日志滚动的 FileHandler 类,分别是 RotatingFileHandler 和 TimedRotatingFileHandler,它就可以解决这个尴尬的问题。

  • RotatingFileHandler 的滚动时刻是日志文件的大小达到一定值,当达到指定值的时候,RotatingFileHandler会将日志文件重命名存档,然后打开一个新的日志文件。
  • TimedRotatingFileHandler 是当某个时刻到来时就进行滚动,同 RotatingFileHandler 一样,当滚动时机来临时,TimedRotatingFileHandler 会将日志文件重命名存档,然后打开一个新的日志文件。

​在实际应用中,我们通常会根据时间进行滚动,以下实例也以时间滚动为例,按大小滚动的同理:

import logging
from logging.handlers import TimedRotatingFileHandler

my_logger = logging.getLogger('A.C,B')
my_logger.setLevel('INFO')

# 创建一个处理器,使用时间滚动的文件处理器
log_file_handler = TimedRotatingFileHandler(filename='log.log', when='D', interval=1, backupCount=10)
# log_file_handler.suffix = "%Y-%m-%d"
# log_file_handler.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}.log$")
log_file_handler.setLevel("ERROR")
my_logger.addHandler(log_file_handler)

# 设置一个格式,并设置到处理器上
formatter = logging.Formatter('%(asctime)s - [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s')
log_file_handler.setFormatter(formatter)

my_logger.debug('这是logger1-DEBUG等级的信息')
my_logger.info('这是logger1-INFO等级的信息')
my_logger.warning('这是logger1-WARNING等级的信息')
my_logger.error('这是logger1-ERROR等级的信息')
my_logger.critical('这是logger1-CRITICAL等级的信息')

​参数说明:

filename:日志文件名;

when:是一个字符串,用于描述滚动周期的基本单位,字符串的值及意义如下:

  • S - Seconds
  • M - Minutes
  • H - Hours
  • D - Days
  • midnight - roll over at midnight
  • W{0-6} - roll over on a certain day; 0 - Monday

interval: 滚动周期,单位由when指定,比如:when='D',interval=1,表示每天产生一个日志文件;

backupCount: 表示日志文件的保留个数;

​除了上述参数之外,TimedRotatingFileHandler还有两个比较重要的成员变量,它们分别是suffix和extMatch。suffix是指日志文件名的后缀,suffix中通常带有格式化的时间字符串,filename和suffix由“.”连接构成文件名(例如:filename="test", suffix="%Y-%m-%d.log",生成的文件名为test.2020-08-01.log。extMatch是一个编译好的正则表达式,用于匹配日志文件名的后缀,它必须和suffix是匹配的,如果suffix和extMatch匹配不上的话,过期的日志是不会被删除的。比如,suffix=“%Y-%m-%d.log”, extMatch的只能是re.compile(r"^\d{4}-\d{2}-\d{2}.log$")。默认情况下,在TimedRotatingFileHandler对象初始化时,suffxi和extMatch会根据when的值进行初始化:

S:suffix="%Y-%m-%d_%H-%M-%S",extMatch=r"\^d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}";
M:suffix="%Y-%m-%d_%H-%M",extMatch=r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}";
H:suffix="%Y-%m-%d_%H",extMatch=r"^\d{4}-\d{2}-\d{2}_\d{2}";
D:suffxi="%Y-%m-%d",extMatch=r"^\d{4}-\d{2}-\d{2}";
MIDNIGHT:"%Y-%m-%d",extMatch=r"^\d{4}-\d{2}-\d{2}";
W:"%Y-%m-%d",extMatch=r"^\d{4}-\d{2}-\d{2}";

​如果对日志文件名没有特殊要求的话,可以不用设置suffix和extMatch,如果需要,一定要让它们匹配上。

八、模块封装

​一次封装,一劳永逸,之后直接调用即可,封装内容按需。

import logging
from logging.handlers import TimedRotatingFileHandler


class MyLogger(object):

    @staticmethod
    def create_logger():
        my_logger = logging.getLogger("my_logger")
        my_logger.setLevel("DEBUG")
        # 控制台处理器
        stream_handler = logging.StreamHandler()
        stream_handler.setLevel("ERROR")
        my_logger.addHandler(stream_handler)
        # 使用时间滚动的文件处理器
        log_file_handler = TimedRotatingFileHandler(filename='log.log', when='D', interval=1, backupCount=10)
        log_file_handler.setLevel("INFO")
        my_logger.addHandler(log_file_handler)
        
        formatter = logging.Formatter('%(asctime)s - [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s')
        stream_handler.setFormatter(formatter)
        log_file_handler.setFormatter(formatter)

        return my_logger

以上就是如何理解python接口自动化之logging日志模块的详细内容,更多关于python 接口自动化 logging日志模块的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python实现对一个完整url进行分割的方法
Apr 29 Python
在Python中定义和使用抽象类的方法
Jun 30 Python
Django URL传递参数的方法总结
Aug 28 Python
简单谈谈Python流程控制语句
Dec 04 Python
Python中循环引用(import)失败的解决方法
Apr 22 Python
python简单实现AES加密和解密
Mar 28 Python
利用python Selenium实现自动登陆京东签到领金币功能
Oct 31 Python
PyCharm 无法 import pandas 程序卡住的解决方式
Mar 09 Python
python同时遍历两个list用法说明
May 02 Python
python中的列表和元组区别分析
Dec 30 Python
教你如何使用Python Tkinter库制作记事本
Jun 10 Python
如何在Python中妥善使用进度条详解
Apr 05 Python
python基于turtle绘制几何图形
详解Flask开发技巧之异常处理
Jun 15 #Python
Python Pandas常用函数方法总结
Jun 15 #Python
深入理解python协程
Jun 15 #Python
2021年最新用于图像处理的Python库总结
Python中的xlrd模块使用整理
Jun 15 #Python
浅谈python中的多态
Jun 15 #Python
You might like
php学习之function的用法
2012/07/14 PHP
解析php中反射的应用
2013/06/18 PHP
php设计模式之单例、多例设计模式的应用分析
2013/06/30 PHP
php读取torrent种子文件内容的方法(测试可用)
2016/05/03 PHP
PHP处理数组和XML之间的互相转换
2016/06/02 PHP
JS 文件本身编码转换 图文教程
2009/10/12 Javascript
Jquery 常用方法经典总结
2010/01/28 Javascript
Javascript base64编码实现代码
2011/12/02 Javascript
js读取被点击次数的简单实例(从数据库中读取)
2014/03/07 Javascript
深入浅析Node.js 事件循环
2015/12/20 Javascript
IScroll5 中文API参数说明和调用方法
2016/05/21 Javascript
JS多文件上传的实例代码
2017/01/11 Javascript
详解Vue 非父子组件通信方法(非Vuex)
2017/05/24 Javascript
highcharts 在angular中的使用示例代码
2017/09/20 Javascript
微信小程序实现验证码获取倒计时效果
2018/02/08 Javascript
JavaScript面向对象继承原理与实现方法分析
2018/08/09 Javascript
Vue常用指令详解分析
2018/08/19 Javascript
微信小程序学习笔记之函数定义、页面渲染图文详解
2019/03/28 Javascript
ES6知识点整理之对象解构赋值应用示例
2019/04/17 Javascript
改进 JavaScript 和 Rust 的互操作性并深入认识 wasm-bindgen 组件
2019/07/13 Javascript
VUE中使用HTTP库Axios方法详解
2020/02/05 Javascript
TF-IDF与余弦相似性的应用(一) 自动提取关键词
2017/12/21 Python
python之matplotlib学习绘制动态更新图实例代码
2018/01/23 Python
python实现简易版计算器
2020/06/22 Python
Windows下anaconda安装第三方包的方法小结(tensorflow、gensim为例)
2018/04/05 Python
Python模拟浏览器上传文件脚本的方法(Multipart/form-data格式)
2018/10/22 Python
自定义django admin model表单提交的例子
2019/08/23 Python
Python lxml模块的基本使用方法分析
2019/12/21 Python
python爬虫爬取某网站视频的示例代码
2021/02/20 Python
美国婚礼装饰和活动用品批发供应商:Event Decor Direct
2018/10/12 全球购物
Currentbody美国/加拿大:美容仪专家
2020/03/09 全球购物
励志演讲稿500字
2014/08/21 职场文书
公司法定代表人授权委托书
2014/09/29 职场文书
幼儿园大班毕业评语
2014/12/31 职场文书
年度考核登记表个人总结
2015/03/06 职场文书
Mysql MVCC机制原理详解
2021/04/20 MySQL