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

代码需要经历开发、调试、审查、测试或者上线等不同阶段,在“测试”时,可能只想看警告和错误信息,然而在“调试”时,可能还想看到跟调试相关的信息。如果想打印出使用的模块以及代码运行的时间,那么代码很容易变得混乱。使用logging日志模块,就能很容易地解决

一、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个等级的日志:

1

2

3

4

5

6

7

8

9

10

11

12

13

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

三、日志收集器

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

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

1

2

3

4

5

6

7

8

9

10

11

# 获取默认的日志收集器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,如下:

1

2

3

4

5

6

7

8

9

10

11

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:移除处理器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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

五、日志过滤器

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

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: 打印日志信息

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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 会将日志文件重命名存档,然后打开一个新的日志文件。

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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的值进行初始化:

1

2

3

4

5

6

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,如果需要,一定要让它们匹配上。

八、模块封装

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你!【100%无套路免费领取】

loggingPython内置的模块,它提供了一个灵活的日志记录系统。在接口自动化测试中,我们可以使用logging模块来输出测试日志,以便于调试和分析测试结果。下面是一个简单的logging封装调用示例: ```python import logging class Logger(object): def __init__(self, logger_name): self.logger = logging.getLogger(logger_name) self.logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) console_handler.setFormatter(formatter) file_handler = logging.FileHandler(filename='test.log') file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(formatter) self.logger.addHandler(console_handler) self.logger.addHandler(file_handler) def get_logger(self): return self.logger ``` 在上面的代码中,我们定义了一个Logger类,它接受一个logger_name参数,并初始化一个logger对象。我们可以通过调用get_logger()方法来获取这个logger对象。 在初始化logger对象时,我们设置了logger的日志级别为DEBUG,这意味着logger会记录所有级别为DEBUG及以上的日志。我们还定义了两个handler,一个是console_handler,它将日志输出到控制台;另一个是file_handler,它将日志输出到文件中。我们设置了两个handler的日志级别都为DEBUG,并且使用了同一个formatter来格式化日志输出。 在接口自动化测试中,我们可以使用Logger类来记录测试日志。例如: ```python logger = Logger('test').get_logger() logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message') ``` 上面的代码会输出不同级别的日志信息,并分别输出到控制台和文件中。我们可以通过分析这些日志信息来诊断和调试测试问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码小怡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值