软硬件环境
- ubuntu 19.04 64bit
- anaconda3 with python 3.7.3
- logging 0.5.1.2
简介
软件运行时难免出现问题,日志是追踪问题的一种方式。不管是在软件的开发阶段、调试阶段或者上线后,日志都非常重要。当程序crash掉而你没有保存日志,那将是灾难性的,损失将非常巨大,而且几乎没有可能找到问题的所在。
print语句可以用来输出调试信息,但是它不是一个好的选择。在简单的脚本中它可能管用,但是随着项目的变大、变复杂,print不会被采用。
python中有一个内置模块logging,它可以将程序运行的信息写入到文件或者其它输出流(如标准输出stdout)当中。
logging消息的级别
按照消息的严重程度,可分为
- Debug : 详细的信息,调试阶段常用
- Info : 程序正常运行的一些信息
- Warning : 警告信息,代码可以继续运行,但是结果可能不是你想要的
- Error : 程序已经出现错误
- Critical : 非常严重的错误,程序可能无法继续运行
在logging中,各级别又对应了一个整数,如下表
| 级别 | 整数 |
|---|---|
| NOSET | 0 |
| DEBUG | 10 |
| INFO | 20 |
| WARNING | 30 |
| ERROR | 40 |
| CRITICAL | 50 |
代码实践
# 导入模块
import logging
# 创建并配置logger,保存到文件
logging.basicConfig(filename="log.txt",
format='%(asctime)s %(message)s',
filemode='w')
# 创建一个对象,参数传入__name__,在模块中就是模块的名称
logger=logging.getLogger(__name__)
# 设置消息的日志层级,在这里,所以高于DEBUG层级的消息都会被写入文件
logger.setLevel(logging.DEBUG)
# 测试
logger.debug("This is debug message.")
logger.info("This is info message.")
logger.warning("This is warning message.")
logger.error("This is error message.")
logger.critical("This is critical message.")
程序执行后,log.txt文件内容为
2019-08-20 17:34:54,362 This is debug message.
2019-08-20 17:34:54,362 This is info message.
2019-08-20 17:34:54,362 This is warning message.
2019-08-20 17:34:54,362 This is error message.
2019-08-20 17:34:54,362 This is critical message.
Logger对象和Handler对象都可以设置级别,而默认Logger对象级别为30 ,也即WARNING,默认Handler对象级别为0,也即NOTSET。logging模块这样设计是为了更好的灵活性,比如有时候我们既想在控制台中输出DEBUG级别的日志,又想在文件中输出WARNING级别的日志。可以只设置一个最低级别的Logger对象,两个不同级别的Handler对象,示例代码如下
import logging
import logging.handlers
logger = logging.getLogger("__name__")
# 标准输出
handler1 = logging.StreamHandler()
# 输出到文件
handler2 = logging.FileHandler(filename="test.txt")
logger.setLevel(logging.DEBUG)
handler1.setLevel(logging.WARNING)
handler2.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s")
handler1.setFormatter(formatter)
handler2.setFormatter(formatter)
logger.addHandler(handler1)
logger.addHandler(handler2)
logger.debug('This is debug message.')
logger.info('This is info message.')
logger.warning('This is warning message.')
logger.error('This is error message.')
logger.critical('This is critical message.')
如果将日志保存在一个文件中,那么时间一长,或者日志一多,单个日志文件就会很大,既不利于备份,也不利于查看。我们会想到能不能按照时间或者大小对日志文件进行划分呢?答案肯定是可以的。logging.handlers文件中提供了TimedRotatingFileHandler和RotatingFileHandler类分别可以实现按时间和大小划分。
在上面的代码块中修改handler2
# 每隔500字节保存成一个日志文件,备份文件为3个
handler2 = logging.handlers.RotatingFileHandler("test.txt", mode="w", maxBytes=500, backupCount=3)
# 每隔1个小时,保存一个日志文件,备份文件为3个
handler2 = logging.handlers.TimedRotatingFileHandler("test.txt", when="H", interval=1, backupCount=3)