前言
距离上一篇博客也是一年半过去了,真的是鸽了非常久…最近在学习一个开源项目的时候对logging有了更深的理解,决定上班摸鱼写篇博客来讲讲。
logging库的好处
python新手可能会觉得:我有print
函数了,啥不能解决?诚然,写代码的都知道print
大法好,没事儿print
/console.log
/std::cout
一下有益身心健康。但是logging
库给予了我们一个灵活且标准的事件记录系统——所有的Python模组都能参与到logging当中来,所以当你在编写自己的项目且用到第三方库的时候,logging是非常统一的;此外,logging还提供了事件信息的格式化输出、输出目的地选择、输出信息的过滤等功能,这些要用print
去一一实现可是很费时间的。
基础教学
最最基本的logging使用方式,就是import它,然后调用内置的函数就可以。下面5个函数的名字,正好对应了信息的严重性等级:
import logging
logging.debug("This is a debug message") # 输出DEBUG级别记录,一般用于问题诊断
logging.info("This is an info message") # 输出INFO级别记录,用于记录程序正常运行
logging.warning("This is a warning message") # 输出WARNING级别记录,用于记录运行出现的异常/需要注意的地方,但不影响运行
logging.error("This is an error message") # 输出ERROR级别记录,一般意味着程序不能执行某些功能,比如某函数执行错误等
logging.critical("This is a critical message") # 输出CRITICAL级别记录,表明程序已经不能继续运行
可以看到输出:
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical message
为什么尝试了5个函数,输出只有3条记录?那是因为logging库的默认输出级别是WARNING的,所以DEBUG/INFO级别的消息就被过滤了。后面会介绍如何配置logging来避免这种过滤。
再看一下默认消息的格式:[level]:[logger]:[message]
分别代表了消息的严重性等级、logger和消息本身。Logger是真正执行记录动作的对象,后面也会讲。这里只需要知道,我们在调用以上5个函数时,是root logger完成了记录动作。
进阶:配置logging行为
接下来我们想对logging的行为进行配置,完成诸如log到文件里、更改消息格式这样的行为。这里需要用到一个函数:logging.basicConfig
。它接受一些键值对,私底下为root logger完成一些配置。比较常用的key有:
key | 释义 |
---|---|
*filename | 一串文件名,表示记录到该文件内 |
*filemode | 文件打开的模式,默认为‘a’,即为内容追加 |
*level | logging的严重性等级 |
*format | logging输出消息的格式的配置字符串,具体格式见下面Formatter内容 |
*datefmt | 描述日期和时间的格式的字符串,具体格式见time.strftime |
*encoding | 3.9新加的参数,描述记录到文件时候用的编码,比如’utf-8’ |
style | 当format被指定时,用这种方式进行字符串格式化。可使用‘%‘或者‘{’或者‘$’。默认为‘%’。 |
stream | 使用指定的流来初始化流处理器(StreamHandler)。与filename不兼容 |
handlers | 使用的一系列处理器(Handler)。与stream与filename不兼容 |
force | 布尔值,如果为True,则root logger里面已存在的处理器全部都被删除,然后再执行配置 |
errors | 如果在使用filename的同时使用了这个键,则它的键值会在创建文件处理器(FileHandler)时候用到 |
上面打了*号的键,是我们比较常用的;剩下的那些要么不常用,要么得随着深入了解logging才会理解其含义。
需要注意的点:
logging.basicConfig
函数必须在任何debug()
、info()
这样的函数之前,不然这些函数会自己用默认参数调用basicConfig
;- 在多线程情况下,
logging.basicConfig
必须在主线程里调用,且在其他子线程启动之前。希望大家永远不要感受多线程/多进程的痛苦。
我们对基础教学里的例子做点改进:
import log