当前位置: 首页 > news >正文

logging:报告状态、错误和信息消息

文章目录

  • 一、日志系统的组成:Logger / LogRecord / Handler / Formatter
  • 二、将日志记入文件:logging.basicConfig()
    • 1、参数 level:设置日志的 「最低记录级别」
    • 2、参数 format:定义日志的输出格式
    • 3、参数 datefmt:指定 %(asctime)s 占位符的时间格式
    • 4、参数 filename:指定日志的输出文件路径
    • 5、参数 filemode:指定日志文件的打开模式
  • 三、自动轮转日志文件:logging.handlers.RotatingFileHandler()
    • 1、参数 filename:主日志文件路径
    • 2、参数 maxBytes:单个日志文件的最大字节数
    • 3、参数 maxBytes:单个日志文件的最大字节数
  • 四、日志级别:NOTSET / DEBUG / INFO / WARNING / ERROR / CRITICAL
  • 五、对日志记录器实例命名:loggerx = logging.getLogger("name")
  • 六、日志树:树形结构,处理器共享,差异化配置
  • 七、与 warnings 模块集成:logging.captureWarnings(True)

logging模块定义了一个标准 API,用来报告错误和状态信息。通过标准库模块来提供日志 API,使得所有的 Python 模块都可以参与日志记录。

import logging

一、日志系统的组成:Logger / LogRecord / Handler / Formatter

日志系统由4种相互作用的对象类型构成。

任何需要记录日志的模块或应用,都可以使用Logger(日志记录器)实例向日志中添加信息。调用日志记录器时会创建一个LogRecord(日志记录),该对象会在内存中暂存日志信息,直至信息被处理。一个Logger可以配置多个Handler(处理器)对象,这些处理器负责接收并处理日志记录。而Handler会借助Formatter(格式化器)将日志记录转换为可供输出的消息。

为方便理解日志系统逻辑,对上述术语进行补充说明:

  • Logger(日志记录器):日志系统的 “入口”,通过调用其方法发起日志记录请求,是开发者直接操作的核心对象。
  • LogRecord(日志记录):日志的 “数据载体”,自动封装日志的级别、内容、时间戳、调用位置等信息,是在系统内部传递的核心数据结构。
  • Handler(处理器):日志的 “分发器”,决定日志的输出目的地(如控制台、文件、网络),一个Logger可配置多个Handler实现 “多端输出”(如同时打印到控制台并写入文件)。
  • Formatter(格式化器):日志的 “美化器”,定义日志输出的字符串格式,使日志内容更易读、易解析。

这四种对象协同工作,形成了 “发起记录→封装数据→分发处理→格式化输出” 的完整日志流程。

二、将日志记入文件:logging.basicConfig()

使用logging模块的basicConfig()函数可以建立默认处理器,将日志信息写入一个文件。接下来对该函数中的常用参数进行具体介绍。

1、参数 level:设置日志的 「最低记录级别」

参数level用于设置日志的 最低记录级别,只有级别大于或等于该值的日志才会被记录。

日志级别「从低到高」的排序为:DEBUG < INFO < WARNING < ERROR < CRITICAL

2、参数 format:定义日志的输出格式

参数format用于定义日志的输出格式,通过占位符指定要包含的日志信息。常用的占位符有:

  • %(asctime)s:日志记录的时间,具体格式由参数datefmt控制
  • %(message)s:日志的具体内容
  • %(levelname)s:日志级别,如INFO
  • %(filename)s:产生日志的文件名称
  • %(threadName)s:当前线程的名称

3、参数 datefmt:指定 %(asctime)s 占位符的时间格式

参数datefmt用于指定%(asctime)s占位符的时间格式,只有在参数format中包含%(asctime)s时,该参数才会生效。

4、参数 filename:指定日志的输出文件路径

参数filename用于指定日志的输出文件路径,此时日志不会打印到控制台,而是写入该参数指向的文件中。若不指定此参数,日志默认输出到控制台(终端)。

5、参数 filemode:指定日志文件的打开模式

参数filemode用于指定日志文件的打开模式,只有设置了参数filename时,该参数才会生效。常用的模式如下:

  • 'a'(append,默认):追加模式,新日志会添加到文件末尾,原有内容保留
  • 'w'(write):覆盖模式,每次运行程序会清空文件原有内容,只保留本次日志
LOG_FILENAME = 'logging_example.out'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,
)logging.debug('This message should go to the log file')with open(LOG_FILENAME, 'rt') as f:body = f.read()# DEBUG:root:This message should go to the log file
print(body)

三、自动轮转日志文件:logging.handlers.RotatingFileHandler()

logging模块的handlers.RotatingFileHandler()日志处理器可以基于配置的文件路径,自动创建新的日志文件,同时保留原来的日志文件。

1、参数 filename:主日志文件路径

最新的日志信息会被写入参数filename指定的主日志文件路径中。

2、参数 maxBytes:单个日志文件的最大字节数

当主日志文件达到参数maxBytes设置的指定字节大小时,日志处理器会通过「增加.1后缀」的方式自动将主日志文件重命名为备份文件。对于已存在的备份文件,也会通过后缀递增的方式进行重命名,如.1变成.2

3、参数 maxBytes:单个日志文件的最大字节数

可以通过参数backupCount规定备份文件的最大数量,避免磁盘空间被过多日志占用。达到最大数量后,最旧的日志文件将会被删除。

import globLOG_FILENAME = 'logging_rotatingfile_example.out'# 创建一个名为 MyLogger 的专属日志记录器,并设置日志记录级别为DEBUG
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)# 为日志记录器添加一个 RotatingFileHandler,实现日志文件自动轮转
handler = logging.handlers.RotatingFileHandler(LOG_FILENAME,   # 日志文件路径maxBytes=20,    # 单个日志文件的最大容量为20字节backupCount=5,  # 最多保留5个备份日志文件数量
)
my_logger.addHandler(handler)   # 将处理器绑定到日志记录器,使日志按处理器规则输出# 产出日志信息
for i in range(20):my_logger.debug('i = %d' % i)# 查找所有以 LOG_FILENAME 为前缀的文件,即主日志文件和所有备份日志文件
# glob.glob() 用于批量查找文件,它按照「Unix 风格的通配符模式」搜索文件路径,返回符合条件的所有文件路径列表
logfiles = glob.glob('%s*' % LOG_FILENAME)
for filename in sorted(logfiles):print(filename)>>> 输出结果:
logging_rotatingfile_example.out
logging_rotatingfile_example.out.1
logging_rotatingfile_example.out.2
logging_rotatingfile_example.out.3
logging_rotatingfile_example.out.4
logging_rotatingfile_example.out.5

四、日志级别:NOTSET / DEBUG / INFO / WARNING / ERROR / CRITICAL

loggingAPI 能够采用不同的日志级别生成不同的日志信息,即使代码中附带了调试信息,也可以通过适当地设置日志级别,避免在生产系统中出现这些调试信息。下表列出了logging定义的日志级别。

日志级别数值
CRITICAL50
ERROR40
WARNING30
INFO20
DEBUG10
NOTSET0

注意:

  • 只有当处理器Handler和日志记录器Logger都被配置为可以发布该级别(及更高级别)的消息时,才会显示这个级别的日志消息。
  • 日志级别中的NOTSET表示未设置具体级别,用于继承上级日志记录器Logger的级别:
    • 当一个子模块Logger被设置为NOTSET时,它会向上查找父级Logger的级别,并使用父级的级别作为自己的有效级别。
    • 只有当所有祖先(父级及往上)Logger的级别都为NOTSET时,才会默认记录所有级别的日志(包括 DEBUG 及以上)。
import sysLEVELS = {'debug': logging.DEBUG,'info': logging.INFO,'warning': logging.WARNING,'error': logging.ERROR,'critical': logging.CRITICAL,
}if len(sys.argv) > 1:level_name = sys.argv[1]level = LEVELS.get(level_name, logging.NOTSET)logging.basicConfig(level=level)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 error message')>>> 输出结果:
$ python /Users/mycomputer/test.py debugDEBUG:root:This is a debug message
INFO:root:This is an info message
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical error message$ python /Users/mycomputer/test.py infoINFO:root:This is an info message
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical error message

五、对日志记录器实例命名:loggerx = logging.getLogger(“name”)

前面所有的日志消息中都包含一个单词root,这是因为代码均使用了根日志记录器。要区分特定日志消息的来源,一个简单的方法是对每个模块使用一个单独的日志记录器对象,发送到日志记录器的消息会包含该记录器的名称。

logging.basicConfig(level=logging.WARNING)logger1 = logging.getLogger('package1.module1')
logger2 = logging.getLogger('package2.module2')logger1.warning('This message comes from one module')
logger2.warning('This comes from another module')>>> 输出结果:
WARNING:package1.module1:This message comes from one module
WARNING:package2.module2:This comes from another module

六、日志树:树形结构,处理器共享,差异化配置

日志记录器Logger实例会根据其名称配置成树形结构,如下图所示。通常每个应用或库都会定义一个基础名称,各个模块的日志记录器则被设置为该基础日志记录器的子级。根日志记录器没有名称。
日志记录器树形结构示例

这种树形结构对日志配置非常实用,因为这意味着每个日志记录器无需配置专属的处理器。如果某个日志记录器没有配置任何处理器,那么日志消息会传递给它的父级日志记录器来处理。因此,对于大多数应用而言,只需要在根日志记录器上配置处理器即可,所有的日志信息都会被收集并发送到同一目标(如指定的日志文件或控制台),如下图所示。
只在根日志记录器上配置处理器

树形结构还支持为应用或库的不同部分设置不同的日志级别、处理器和格式化器,从而控制哪些日志消息会被记录,以及这些消息会输出到哪里,如下图所示。
不同部分设置不同的日志级别和处理器

七、与 warnings 模块集成:logging.captureWarnings(True)

logging模块通过captureWarnings()函数与warnings模块实现集成。该函数会配置warnings模块,让警告信息通过日志系统输出而不是直接输出。

import warningslogging.basicConfig(level=logging.INFO)warnings.warn('This warning is not sent to the logs')logging.captureWarnings(True)# 这条警告信息使用 WARNING 日志级别被发送到一个名为 py.warnings 的日志记录器
warnings.warn('This warning is sent to the logs')>>> 输出结果:
/Users/mycomputer/test.py:8: UserWarning: This warning is not sent to the logswarnings.warn('This warning is not sent to the logs')
WARNING:py.warnings:/Users/mycomputer/test.py:12: UserWarning: This warning is sent to the logswarnings.warn('This warning is sent to the logs')
http://www.dtcms.com/a/365744.html

相关文章:

  • Linux的墙上时钟和单调时钟的区别
  • 检查系统需求
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘isort’问题
  • Linux编程——网络编程(tcp)
  • 演员-评论员算法有何优点?
  • JavaScript原型与原型链:对象的家族传承系统
  • 3-7〔OSCP ◈ 研记〕❘ WEB应用攻击▸REST API概述
  • 漫谈《数字图像处理》之图像清晰化处理
  • 更新远程分支 git fetch
  • 计算机三级网络应用题大题技巧及练习题
  • 【微实验】使用MATLAB制作一张赛博古琴?
  • 最左匹配原则:复合索引 (a,b,c) 在 a=? AND b>? AND c=? 查询下的使用分析
  • 波浪模型SWAN学习(2)——波浪浅化模拟(Shoaling on sloping beach)
  • 14.错误和异常(二)
  • PastePal for Mac 剪贴板历史记录管理器
  • 学习嵌入式第四十五天
  • 设计原则与设计模式
  • flume拓扑结构详解:从简单串联到复杂聚合的完整指南
  • 蓝牙modem端frequency offset compensation算法描述
  • 技术重构人力管理 —— 打造人力资源流程自动化、智能化专业服务方案
  • 小企业环境-火山方舟和扣子
  • 字节跳动后端 一面凉经
  • 数据库与大数据技术栈
  • ElasticSearch倒排索引原理
  • redis中五大数据类型的操作命令
  • 编程基础-eclipse创建第一个程序
  • 【开题答辩全过程】以 基于java的隔离酒店管理系统设计与开发为例,包含答辩的问题和答案
  • 线程通信机制
  • 记录一下node后端写下载https的文件报错,而浏览器却可以下载。
  • 开源与闭源的再对决:从Grok到中国力量,AI生态走向何方?