python进阶之logging日志模块的使用
作者:青铜发条
引言
在软件开发中,日志(Logging)是不可或缺的工具。它帮助我们追踪程序执行流程、诊断错误、监控系统状态,是调试、运维和分析用户行为的关键。Python 内置的 logging 模块功能强大且灵活,远超简单的 print 语句。
一、logging对比print
你可能习惯用 print()
输出信息,但 logging
模块提供了 print
无法比拟的优势:
- 日志级别(Levels):支持
DEBUG
,INFO
,WARNING
,ERROR
,CRITICAL
等级别,可以方便地控制不同环境(开发、测试、生产)输出的信息量。 - 灵活的输出目标(Handlers):日志可以同时输出到控制台、文件、网络、邮件、数据库等,而
print
只能输出到标准输出。 - 丰富的格式化(Formatters):可以自定义日志的输出格式,包含时间、模块名、行号、日志级别等信息。
- 性能:在生产环境中,可以将日志级别设为
WARNING
,此时debug()
调用几乎不消耗性能(因为消息不会被格式化),而print
语句即使注释掉也需要手动操作。 - 结构化与可维护性:
logging
提供了清晰的架构,易于配置和管理,适合大型项目。
二、基本使用方法
2.1 导入 logging 模块
import logging
2.2 日志级别介绍
日志级别用于控制日志的详细程度。logging 模块提供了以下几种日志级别:
级别 | 数值 | 说明 |
---|---|---|
CRITICAL | 50 | 致命,严重错误,程序可能无法继续运行 |
ERROR | 40 | 错误,但程序仍可运行 |
WARNING | 30 | 警告,表示潜在的问题,但程序仍能正常运行。默认级别) |
INFO | 20 | 提示,程序正常运行时的信息 |
DEBUG | 10 | 调试,详细的调试信息,通常用于开发阶段 |
NOTSET | 0 | 继承,继承父记录器的级别 |
注意:默认日志级别是 WARNING,即低于 WARNING 的日志不会被输出。
需要设置日志显示的最低显示级别。如显示所有日志,设置为最低级别DEBUG:
logging.basicConfig(level=logging.DEBUG)
2.3 简单使用示例
快速使用日志的完整功能示例:
import logging logging.basicConfig(level=logging.INFO) logging.debug("这是一条调试信息") logging.info("这是一条普通信息") logging.warning("这是一条警告信息") logging.error("这是一条错误信息") logging.critical("这是一条严重错误信息")
运行结果:
三、logging 模块的核心组件
logging
模块基于一个经典的 生产者-过滤器-处理器 模型,主要由四个核心对象构成:
类 | 说明 | 示例 |
---|---|---|
logging.Logger | 记录器,用于发出日志消息 | logger = logging.getLogger("my_logger") |
logging.Handler | 处理器,决定日志输出位置(如文件、控制台等) | handler = logging.FileHandler("app.log") |
logging.Formatter | 格式化器,控制日志输出的格式 | formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') |
logging.Filter | 过滤器,用于更精细地控制日志记录 | filter = logging.Filter("module.name") |
3.1 Logger (记录器)
角色:应用程序的接口。你通过 Logger 对象调用 debug(), info(), warning(), error(), critical() 方法来记录日志。
关键属性:
- 名称(Name):通常使用 logging.getLogger(__name__) 创建,__name__ 是模块的全名(如 myapp.module),这有助于组织日志层次结构。
- 级别(Level):Logger 有一个日志级别。只有级别大于或等于此级别的日志记录才会被处理。如果 Logger 本身没有设置级别,它会向上传递到父 Logger(最终到根 Logger)。
层级结构:Logger 按名称形成树状结构。myapp 是 myapp.module 的父 Logger。日志消息会沿着这个层级向上传播,除非设置了 propagate=False。
3.2 Handler (处理器)
角色:决定日志消息的最终去向。一个 Logger
可以有多个 Handler
。
常见 Handler:
- StreamHandler:输出到流(如 sys.stdout, sys.stderr)。
- FileHandler:输出到文件。
- RotatingFileHandler:输出到文件,并在文件达到一定大小时轮转。
- TimedRotatingFileHandler:按时间(如每天)轮转日志文件。
- SMTPHandler:通过邮件发送日志。
- SocketHandler / DatagramHandler:通过网络发送日志。
处理器 | 说明 |
---|---|
StreamHandler | 输出到控制台(sys.stdout / sys.stderr) |
FileHandler | 输出到文件(文本) |
RotatingFileHandler | 按大小轮转日志文件 |
TimedRotatingFileHandler | 按时间轮转日志文件 |
SMTPHandler | 通过邮件发送日志 |
SocketHandler / DatagramHandler | 通过网络发送日志 |
NullHandler | 空处理器,用于避免无 handler 时的警告 |
关键属性:
级别(Level):
Handler
也有自己的级别。即使Logger
接受了一条日志,Handler
也会根据自己的级别再次过滤。例如,Logger
级别是DEBUG
,Handler
级别是INFO
,那么DEBUG
级别的日志不会被这个Handler
处理。Formatter:关联一个
Formatter
来格式化日志消息。
3.3 Formatter (格式化器)
角色:定义日志消息的最终输出格式。
格式:使用类似
%(asctime)s - %(name)s - %(levelname)s - %(message)s
的字符串。可以为不同的
Handler
设置不同的Formatter
。例如,文件日志包含详细信息(时间、行号),而控制台日志只显示简洁信息。
Formatter 常用格式字段如下:
字段 | 说明 | 示例输出 |
---|---|---|
%(asctime)s | 日志创建时间 | 2023-01-01 12:00:00,123 |
%(levelname)s | 日志级别名称 | INFO |
%(message)s | 日志消息内容 | 程序启动成功 |
%(name)s | 记录器名称 | my_logger |
%(filename)s | 生成日志的文件名 | app.py |
%(lineno)d | 生成日志的行号 | 42 |
%(funcName)s | 生成日志的函数名 | main |
%(pathname)s | 生成源文件的完整路径 | |
%(module)s | 生成模块名(文件名去掉 .py) | |
%(process)d | 生成进程ID | |
%(thread)d | 生成线程 ID |
3.4 Filter (过滤器)
- 角色:提供更精细的日志过滤机制,可以基于
Logger
名称、日志级别或其他属性进行过滤。 - 使用场景:相对较少直接使用,
Logger
和Handler
的级别通常足够。但可以用于实现复杂逻辑,比如只记录特定用户的日志。
3.5 核心组件快速使用示例
import logging # 1. 获取一个 Logger 实例(通常使用模块名) logger = logging.getLogger(__name__) # 2. 设置 Logger 级别 logger.setLevel(logging.DEBUG) # 3. 创建 Handler (例如,输出到控制台) console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) # Handler 级别 # 4. 创建 Formatter formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_handler.setFormatter(formatter) # 5. 将 Handler 添加到 Logger logger.addHandler(console_handler) # 6. 记录日志 logger.debug("调试信息") logger.info("普通信息") logger.warning("警告信息") logger.error("错误信息") logger.critical("严重错误")
运行结果:
四、高级用法与最佳实践
1、配置分离:将日志配置独立出来
将配置放在单独的文件中,是大型项目的标准做法。推荐使用 dictConfig
。
# logging_config.py import logging from logging.config import dictConfig LOGGING_CONFIG = { "version": 1, "disable_existing_loggers": False, # 避免禁用第三方库日志 "formatters": { "detailed": { "format": "%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s" }, "simple": { "format": "%(name)s - %(levelname)s - %(message)s" } }, "handlers": { "file": { "class": "logging.handlers.RotatingFileHandler", # 轮转文件 "level": "DEBUG", "formatter": "detailed", "filename": "app.log", "maxBytes": 10485760, # 10MB "backupCount": 5, # 保留 5 个备份 "encoding": "utf-8" }, "console": { "class": "logging.StreamHandler", "level": "INFO", "formatter": "simple" } }, "loggers": { "myapp": { # 为你的应用定义 logger "level": "DEBUG", "handlers": ["file", "console"], "propagate": False } } } dictConfig(LOGGING_CONFIG) logger = logging.getLogger("myapp") # 创建全局 logger 实例
在其他模块中使用:
# main.py from logging_config import logger logger.info("应用启动")
2、RotatingFileHandler 分割日志文件
FileHandler
会无限增长文件。使用 RotatingFileHandler
或 TimedRotatingFileHandler
可以自动管理日志文件大小和数量。
3、捕获异常信息
try: result = 1 / 0 except Exception as e: logger.error("发生异常", exc_info=True) # exc_info=True 会自动记录 traceback # 或者使用 # logger.exception("发生异常") # 等价于 logger.error(..., exc_info=True)
4、在多模块项目中使用name
# myapp/utils.py import logging logger = logging.getLogger(__name__) # __name__ 是 'myapp.utils' def some_function(): logger.info("在 utils 模块中执行")
这样日志会清晰地显示来源 myapp.utils - INFO - 在 utils 模块中执行
。
5、避免重复日志
问题:如果 Logger
的 propagate=True
(默认)且父 Logger
也有 Handler
,日志可能被多次输出。
解决方案:在配置中为你的应用 Logger
设置 "propagate": False
。
处理中文 在 FileHandler
或 RotatingFileHandler
中指定 encoding="utf-8"
。
总结
Python 的 logging
模块是一个功能完备、设计精良的日志框架。掌握其核心组件(Logger
, Handler
, Formatter
, Filter
)的工作原理,是构建可靠应用的基础。通过合理的配置(尤其是使用 dictConfig
分离配置),你可以轻松实现:
- 多环境适配:开发时输出
DEBUG
信息,生产时只输出WARNING
及以上。 - 多目标输出:同时将详细日志写入文件,将关键信息输出到控制台。
- 结构化日志:包含时间、位置、级别等上下文信息,便于排查问题。
- 可维护性:配置集中管理,易于调整。
告别 print
,拥抱 logging
,让你的应用拥有清晰、可追溯的“生命日志”!
到此这篇关于python进阶之logging日志模块的使用的文章就介绍到这了,更多相关python logging日志 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!