引言
我们写代码时经常在程序中间歇性地使用 print()
语句来检查不同变量和对象的中间值。它可以帮助我们验证程序是否按照预期运行。不过,日志记录比间歇性打印语句更有益处,因为它能让人更深入地了解事件。
日志
一词指的是记录某一进程中不同中间事件的机制。
记录日志有助于开发人员调试和跟踪应用程序逻辑中的任何错误。
Python
的标准库提供了日志模块 logging
,通过该模块可以生成和记录应用程序日志。
什么时候使用
首先要明确什么时候用什么样的工具:
下表是python官网给出的推荐:
你要执行的任务 | 此任务推荐使用的工具 |
---|---|
对于命令行或程序的应用,结果使用控制台输出 | print() |
报告程序正常运行期间发生的事件(例如,用于状态监控或故障调查) | logging.info() |
基于特定运行时事件发出警告 |
|
报告有关特定运行时事件的错误 | 显式抛出异常:raise |
在不引发异常的情况下报告错误(例如,长期运行的服务器进程中的错误处理程序 | logging.error() 、logging.exception() 或 logging.critical() ,视具体错误和应用领域而定。 |
日志等级划分
日志功能按其跟踪事件的级别或严重程度命名。标准级别及其适用性说明如下(按严重性递增顺序排列):
等级 | 何时使用 | 数值 |
---|---|---|
logging.DEBUG | 用于详细信息的输出,主要用于调试和排查问题 | 10 |
logging.INFO | 提供程序运行时的一般信息,表明程序正常按预期运行 | 20 |
logging.WARNING | 表示某些预期之外但不是致命的情况,需要引起关注。(某个函数使用了废弃的特性;磁盘空间不足) | 30 |
logging.ERROR | 指出发生了一个更严重的问题,但不至于导致程序完全失败。(某个函数无法执行某个操作) | 40 |
logging.CRITICAL | 表示致命的错误,可能导致程序的崩溃。一般用于指出一些需要紧急处理的严重问题。 | 50 |
使用下面语句生成日志信息:
import logging
logging.debug('This is a debug message') # 不会被记录
logging.info('This is an info message') # 不会被记录
logging.warning('This is a warning message') # 会被记录
logging.error('This is an error message') # 会被记录
logging.critical('This is a critical message') # 会被记录
发现结果为:
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical message
我们发现 日志严重性级别: 日志内容
的格式输出了,但是发现只有 WAENING
及以上级别的才显示,这是因为默认日志记录器默认阈值是 WAENING
。会忽略 WAENING
以下的。
基本使用配置
所以需要学习 logging.basicConfig()
来配置日志输出相关的设置,下面是其参数:
参数 | 描述 |
---|---|
filename | 使用指定的文件名创建一个 FileHandler ,而不是 StreamHandler 。 |
filemode | 如果指定了 filename ,则用此模式打开该文件。 默认模式为 'a' 。 |
format | 使用指定的格式字符串作为处理器。 默认格式为 '%(levelname)s:%(message)s' 。 |
datefmt | 使用指定的日期/时间格式,与 time.strftime() 所接受的格式相同。 |
style | 如果指定了 format ,将为格式字符串使用此风格。 '%' –printf()风格, '{' –str.format() '$' –string.Template。 默认为 '%' |
level | 设置根记录器级别为指定的 level |
encoding | 如果此关键字参数与 filename 一同被指定,则其值会在创建 FileHandler 时被使用,因而也会在打开输出文件时被使用。(python3.9中加入) |
stream | 使用指定的流初始化 StreamHandler。 请注意此参数与 filename 不兼容 —— 如果两者同时存在,则会引发 ValueError。 |
详细说明一下一些常用的参数:
-
指定
filename
的话就会输出在指定的文件中,不指定默认是控制台输出: -
如果给了文件名
filemode
就是文件的open()
方式,一般设置为:'a'
:文件用于写入,如果文件存在则在末尾追加。(保留原来的)'w'
:文件用于写入,删除原来的。
-
format
:默认是'%(levelname)s:%(message)s'
-等级:信息:可以选以下参数等:- %(asctime)s:代表日志记录的时间。使用
datefmt
参数设置输出格式。 - %(levelname)s:代表日志级别的名称。
- %(message)s:代表日志消息的文本。
- %(name)s:代表记录器的名称。
- %(filename)s:代表产生日志记录的源文件的文件名。
- %(pathname)s:代表产生日志记录的源文件的完整路径。
- %(funcName)s:代表产生日志记录的函数名称。
- %(lineno)d:代表产生日志记录的源文件中的行号。
- %(process)d:代表进程 ID。
- %(thread)d:代表线程 ID。
- %(asctime)s:代表日志记录的时间。使用
-
style
:就是设置上面的写法,如果占位符想使用 {} 来标识,就设置为'{'
-
level
: 就是设置日志阈值。
下面是一个具体的例子:
import logging
logging.basicConfig(filename='example.log', # 指定日志文件名
filemode='w', # 指定文件打开模式
level=logging.INFO, # 指定日志级别,低于此级别的日志将被忽略
format='{asctime} - {lineno} - {levelname}:{message}', # 指定日志格式
# 时间 - 行号 - 日志级别:日志信息
style='{', # 指定格式字符串的风格
datefmt='%Y-%m-%d %H:%M:%S') # 指定日期格式
logging.debug('This is a debug message') # 低于日志级别,不会被记录
logging.info('This is an info message') # 会被记录
logging.warning('This is a warning message') # 会被记录
logging.error('This is an error message') # 会被记录
logging.critical('This is a critical message') # 会被记录
这个日志信息会被记录在对应文件当中,内容如下:
2023-12-04 18:23:46 - 12 - INFO:This is an info message
2023-12-04 18:23:46 - 13 - WARNING:This is a warning message
2023-12-04 18:23:46 - 14 - ERROR:This is an error message
2023-12-04 18:23:46 - 15 - CRITICAL:This is a critical message