认识 logging 模块
程序运行中需要记录关键信息,例如启动/结束时间、用户操作、错误原因等。日志(logging)是比 print() 更专业、更强大的工具。
基础用法
import logging
logging.warning("这是一个警告信息")
运行结果:
WARNING:root:这是一个警告信息
无需额外配置即可直接使用。默认只显示 WARNING 及以上级别的日志,输出到控制台,格式固定为 级别:logger 名:消息。
日志级别函数
| 函数 | 用途 | 示例 |
|---|---|---|
| logging.debug() | 调试细节(开发时用) | logging.debug("变量 x = %d", x) |
| logging.info() | 一般信息 | logging.info("服务已启动") |
| logging.warning() | 警告(可能有问题) | logging.warning("磁盘空间不足") |
| logging.error() | 错误(功能异常) | logging.error("数据库连接失败") |
| logging.critical() | 严重错误(程序可能崩溃) | logging.critical("配置文件丢失!") |
记忆口诀:D-I-W-E-C(严重性递增)。
设置日志级别
默认不显示 INFO 和 DEBUG,因为 logging 有最低级别设置。使用 basicConfig() 配置:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("调试信息")
logging.info("普通信息")
logging.warning("警告")
输出:
DEBUG:root:调试信息
INFO:root:普通信息
WARNING:root:警告
level=logging.DEBUG 表示显示 DEBUG 及以上所有级别。可选值:DEBUG, INFO, WARNING, ERROR, CRITICAL。
自定义日志格式
默认格式简单,可添加时间、行号、函数名等。
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logging.info("程序开始运行")
输出:
2026-01-14 13:30:45,123 - INFO - 程序开始运行
常用格式占位符:
| 占位符 | 含义 |
|---|---|
| %(asctime)s | 时间 |
| %(levelname)s | 日志级别 |
| %(message)s | 日志内容 |
| %(name)s | logger 名称 |
| %(filename)s | 文件名 |
| %(funcName)s | 函数名 |
| %(lineno)d | 行号 |
详细示例:
format='%(asctime)s - %(name)s - %(funcName)s:%(lineno)d - %(levelname)s - %(message)s'
写入文件
光在控制台看不够,需保存到文件。
方法 1:使用 filename 参数
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(message)s',
filename='my_app.log'
)
logging.info("这条日志会写入文件")
注意:指定 filename 后默认不再输出到控制台。
方法 2:同时输出到文件和控制台
import logging
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
file_handler = logging.FileHandler('app.log')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.info("这条日志会同时出现在控制台和文件中")
这是企业项目中常见的做法。
日志轮转
防止日志文件过大撑爆硬盘,使用 RotatingFileHandler。
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger('my_app')
logger.setLevel(logging.INFO)
handler = RotatingFileHandler(
'app.log',
maxBytes=1_000_000,
backupCount=3
)
handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s'))
logger.addHandler(handler)
for i in range(10000):
logger.info(f"这是第 {i} 条日志")
当 app.log 超过 1MB,系统会自动重命名旧文件并新建空文件,保留指定数量的备份。
记录异常
程序出错时需记录完整堆栈。
错误做法
try:
1 / 0
except Exception as e:
logging.error("出错了:" + str(e))
只有错误信息,缺少堆栈。
正确做法
方法 1:exc_info=True
try:
1 / 0
except Exception:
logging.error("发生异常", exc_info=True)
自动附带完整 traceback。
方法 2:logger.exception()
try:
1 / 0
except Exception:
logging.exception("发生异常")
等价于 error(..., exc_info=True),仅在 except 块中使用。
最佳实践
大项目中,不同模块应有独立的日志命名空间。
utils/db.py:
import logging
logger = logging.getLogger(__name__)
def connect():
logger.info("正在连接数据库")
main.py:
import logging
from utils.db import connect
logging.basicConfig(level=logging.INFO)
connect()
好处:可以单独控制某个模块的日志级别。
总结要点
- 使用 logging 而非 print,更专业且线程安全。
- 五大函数按严重程度选择:debug/info/warning/error/critical。
- 用 basicConfig() 快速配置,但只能调用一次。
- 格式用 format 参数或 Formatter,推荐包含时间、级别、消息。
- 写文件用 FileHandler 或 filename,生产环境必须持久化。
- 记录异常用 exc_info=True 或 exception(),否则看不到错误原因。
