调试模块——logging

前言

在没有学 logging 日志模块之前

为了发现脚本程序中的的bug,通常会用下面几种办法来调试,检查变量值,或者捕获到一些难以察觉的错误

  • print()

  • raise Exception()

  • try: raise Exception() except Exception as err:

  • assert 表达式, “message”


实例

  • 实例代码功能,计算“数的阶乘”;
#!python3
def factorial(n):
	total = 1
	for i in range(n + 1):
		total *= i
	return total

print('7! = ' + str(factorial(7)))

但是代码中存在的问题是 range(n+1),由于 range 函数,迭代生成 0 ~ n 的一组数 一开始 i 被赋值为 0,total * i 就等于零,会导致最终结果等于零,这显然是不正确的 正常代码结果

5! = 1 * 2 * 3 * 4 * 5 = 120

异常代码结果

5! = 0 * 2 * 3 * 4 * 5 = 0

现在来调试代码可能存在的问题,就要看 i 每一次的变量值,和 total 相应的结果。


logging 日志记录模块

一、基本用法

#!python3
import logging
logging.basicConfig(
					level=logging.DEBUG, 
					format="%(asctime)s - [%(levelname)s] - %(message)s"
                    )
#logging.disable(logging.CRITICAL)
logging.debug('程序开始')

def factorial(n):
	logging.debug('factorial函数开始运行(%s)' % (n))
	total = 1
	for i in range(1, n + 1):
		total *= i
		logging.debug('i 为 ' + str(i) + ', total 为 ' + str(total))
	logging.debug('factorai函数运行结束(%s)' % (n))
	return total

print('7! = ' + str(factorial(7)))
logging.debug('程序结束.')

运行效果

2019-07-16 20:28:45,072 - [DEBUG] - 程序开始
2019-07-16 20:28:45,073 - [DEBUG] - factorial函数开始运行(5)
2019-07-16 20:28:45,073 - [DEBUG] - i 为 0, total 为 0
2019-07-16 20:28:45,073 - [DEBUG] - i 为 1, total 为 0
2019-07-16 20:28:45,073 - [DEBUG] - i 为 2, total 为 0
2019-07-16 20:28:45,073 - [DEBUG] - i 为 3, total 为 0
2019-07-16 20:28:45,073 - [DEBUG] - i 为 4, total 为 0
2019-07-16 20:28:45,073 - [DEBUG] - i 为 5, total 为 0
2019-07-16 20:28:45,073 - [DEBUG] - factorai函数运行结束(5)
5! = 0
2019-07-16 20:28:45,074 - [DEBUG] - 程序结束.

所以,我们可以看出,i 变量的数值从一开始就是 0 ,所以我们尽快定位问题所在。 并修改代码为

for i in rang(1, n+1):

二、日志级别(由低到高)

级别函数调用描述
DEBUGlogging.debug()最低级别。用于小细节。通常只有在诊断问题时,你才会关心这些消息
INFOlogging.info()用于记录程序中一般事件的信息,或确认一切工作正常
WARNINGlogging.warning()用于表示可能的问题,它不会阻止程序的工作,但将来可能会
ERRORlogging.error()用于记录错误,它导致程序做某事失败
CRITICALlogging.critical()最高级别。用于表示致命的错误,它导致或将要导致程序完全停止工作

三、将debug日志写到文件中

logging.basicConfig(filename='D:\\py\\Auto\\debug\\myProgramLog.txt',
					level=logging.DEBUG, 
					format="%(asctime)s - [%(levelname)s] - %(message)s")

将 filename 设置好后,所有 debug 消息就会写入外部的文本文件,命令行就不会显示了。

四、调试"开关"

这个功能,才是以后不用 print 来调试的正真的关键

logging.disable(logging.CRITICAL)

通常将它,放在 loggin.basicConfig() 下一行,并且先注释掉。(可以看下基本用法中的例子) 调试完成后,取消注释,禁用所有调试信息输出。

总结

  • logging.disable(logging.CRITICAL),会禁止显示,当前级别,以及比当前级别低的调试信息。
  • format 可以自定义消息输出的格式
logging.basicConfig(
                    level=logging.DEBUG, 
                    format="%(asctime)s - [%(levelname)s] - %(message)s"
                    )

format 设置好后字符串格式后,如下输出

2019-07-16 20:28:45,073 - [DEBUG] - i 为 0, total 为 0
%(asctime)s --> 2019-07-16 20:28:45,073
\-
[%(levelname)s] --> [DEBUG]
\-
%(message)s --> logging.debug('i 为 ' + str(i) + ', total 为 ' + str(total))