级别 | 何时使用 |
---|---|
DEBUG | 细节信息,仅当诊断问题时使用 |
INFO | 确认程序按预期运行 |
WARNING | 表明已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行 |
ERROR | 由于严重的问题,程序的某些功能已经不能正常执行 |
CRITICAL | 严重的错误,表明程序已不能继续执行 |
默认等级是“WARNING”,意味着只会跟踪该级别及以上的事件(由上倒下等级以此递增),除非更改日志配置。
1. quick start
>>> import logging
>>> logging.warning("warning")
WARNING:root:warning
>>> logging.info("information")
>>>
注意这里只有warning的信息打印出来了。如前面所说,默认等级是“WARNING”,只会追踪该级别及以上的事件,所以info信息没有被打印出来。
其中WARNING是记录级别;root代表打印的模块来源(没有显示设置,显然是默认值,甚至不是当前模块的名称);warning就是我们显示打印的数据信息了。
2. 记录日志到文件
import logging
logging.basicConfig(filename='pycode.log', level=logging.DEBUG)
logging.warning('warning')
logging.info('information')
logging.debug('debug')
通过设置logging的基本配置可以将记录重定向到文件中。同时可以通过level指定打印级别。
# pycode.log
WARNING:root:warning
INFO:root:information
DEBUG:root:debug
注意到,此时在文件中的打印级别已经降为 DEBUG了。该方法也适用在命令行中修改打印级别。
但有个需要注意的点:对basicConfig的调用应该在debug(),info()等函数前面。basicConfig是一次性的配置,只有第一次调用会进行操作,随后的调用不会产生有效操作。
什么意思呢?举个例子:
>>> import logging
>>> logging.warning("123")
WARNING:root:123
>>> logging.info("123") # 不会有输出
>>> logging.basicConfig(level=logging.DEBUG)
>>> logging.info("123") # 依旧不会有输出
另一个例子:
>>> import logging
>>> logging.basciConfig(level=loggin.DEBUG)
>>> logging.warning("123")
WARNING:root:123
>>> logging.info("123")
INFO:root:123
在第一次调用logging.info()、warning()等函数的时候,就会调用内置的basicConfig。此时就已经固化打印级别为WARNING了,即使后面再次显式调用basicConfig也不会有效。
命令行指定级别:除了通过basicConfig设置level,也可以在执行Python程序的时候,通过命令行参数指定。
$ 设置logging打印级别为INFO
$ python3 pycode.py --log=INFO
追加打印:此外,记录输出到文件中,默认是追加打印的。如果希望重新记录,可以这样:
logging.basicConfig(filename='pycode.log', filemode='w', level=logging.DEBUG)
3. 多模块打印
# main.py
import logging
import somelib
logging.basicConfig(level=logging.INFO)
def main():
logging.info("py01")
py02.do_something()
if __name__ == '__main__':
main()
# ---------------------------
# somelib.py
import logging
def do_something():
logging.info("py02")
输出:
# pycode.log
INFO:root:py01
INFO:root:py02
可以看到,多模块的信息都能正常打印到日志文件中。但很明显可以发现不论是从哪个模块输出,日志记录中显示的都是root。所以目前还不能跟踪记录打印的模块来源。
4. 定义打印格式
前面出现的打印信息基本上是:记录级别:模块来源:记录信息
同样可以在basicConfig中定义打印的格式:
>>> import logging
>>> logging.basicConfig(format='%(asctime)s : %(name)s : %(message)s', level=logging.INFO)
>>> logging.info("123")
2020-06-19 22:38:16,048 : root : 123
可以看到,此时展示了打印时间,模块来源及记录信息。
格式配置属性:
格式 | 描述 |
---|---|
%(asctime)s | 调用消息记录打印时的时间(格式化后的时间) |
%(created)f | 调用消息记录打印时的时间(未格式化的描述,相当于time.time()) |
%(filename)s | 调用消息记录打印的文件名称(在哪个文件里面) |
%(funcName)s | 调用消息记录打印的函数名称(在哪个函数里面) |
%(levelname)s | 消息记录级别(DEBUG,INFO,WARNING,ERROR,CRITICAL) |
%(levelno)s | 消息记录级别的数字号(DEBUG=10,INFO=20,WARNING=30,ERROR=40,CRITICAL=50) |
%(lineno)d | 调用消息记录打印的行数(在哪一行打印的) |
%(message)s | 待打印的自定义消息 |
%(module)s | 调用消息记录的模块名 |
%(msecs)d | 调用消息记录打印时间的毫秒部分 |
%(name)s | 打印消息的logger对象名称(自定义的,默认是root) |
%(pathname)s | 调用消息记录的文件路径 |
%(process)d | 进程ID |
%(processName)s | 进程名 |
%(relativeCreated)d | 相对logging模块被加载到打印消息记录时的相对时间(毫秒) |
%(thread)d | 线程ID |
%(threadName)s | 线程名 |
此时,为了跟踪打印消息的来源,我们可以组织一个这样的格式串:
# main.py
import logging
import somelib
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s: %(name)s: %(levelname)s: %(message)s")
logger = logging.getLogger("main123")
def main():
logger.info("py01")
somelib.do_something()
if __name__ == '__main__':
main()
# ------------------------------
# somelib.py
import logging
logger = logging.getLogger("pylib")
def do_something():
logger.info("py02")
# ------------------------------
# 输出
2020-06-19 23:26:27,263: main123: INFO: py01
2020-06-19 23:26:27,264: pylib: INFO: py02
有其他的需求,也可以根据上面列出来的属性自行搭配。
[1] 日志基础教程-官方文档
[2] LogRecord属性-官方文档