软硬件环境
- 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)