不少新手习惯使用 print() 调试自己的 Python 项目吗。在本地测试时,print("执行到第3步")这种 似乎很方便,但一旦项目上线,这些信息就会丢失在控制台中。当错误发生时,将无法回溯"什么时候错了、错在哪",项目如同缺少了"黑匣子"。
专业的日志管理能记录项目运行的"台账",不仅能分级(如普通信息、错误警告),还能持久化存储,让我们在问题发生时能按时间、按模块快速定位。
本文将入门 Python 日志管理:从为什么需要日志开始,介绍 2 个主流库(logging 和 loguru)的代码实例,并总结 5 条项目级的日志规范。
一、为什么日志(Logging)远胜于打印(Print)?
print 是一个"临时便利贴",而日志是项目的"正式台账"。对于任何非临时脚本的项目,日志管理都是必需的。
| 对比项 | print() 调试 | 日志管理工具 (Logging) |
|---|---|---|
| 信息分级 | 没有分级(所有输出都一样) | 能 (DEBUG, INFO, ERROR 等) |
| 持久化存储 | 只在控制台显示,关闭即丢失 | 能 (存到文件、数据库等) |
| 配置灵活性 | 格式固定(只能打印内容) | 能 (添加时间、模块名、行号) |
| 线上可用性 | 几乎为零(无法追溯历史) | 高 (快速排查线上问题) |
二、新手入门:2 个主流日志库
Python 日志库分为自带的标准库和功能更简洁的第三方库。掌握这两个,足以应对 90% 的项目场景。
2.1 选项 1:自带库 logging (功能全面,无需安装)
logging 是 Python 的标准库,功能强大且高度可定制,但配置相对繁琐。
1. 基础用法:3 行代码输出到控制台
logging 默认只显示 WARNING 及以上级别的日志,可以通过 basicConfig 调整。
python
# 1. 导入自带的 logging 库
import logging
# 2. 配置日志级别(关键!低于这个级别的日志不会输出)
# 级别从低到高:DEBUG < INFO < WARNING < ERROR < CRITICAL
logging.basicConfig(level=logging.DEBUG) # 这里设为DEBUG,所有级别都能输出
# 3. 输出不同级别的日志
logging.debug("这是DEBUG级日志:开发时调试用,比如「变量a=10」")
logging.info("这是INFO级日志:正常运行信息,比如「服务启动成功」")
logging.warning("这是WARNING级日志:潜在问题,比如「内存快满了」")
logging.error("这是ERROR级日志:功能出错,比如「数据库连接失败」")
logging.critical("这是CRITICAL级日志:致命错误,比如「服务崩溃」")
-
优点:简单,一行代码就能用。
-
缺点(也是实际项目的痛点):
-
默认把所有日志都混在一起
-
通常只能输出到一个地方(要么控制台,要么文件,很难同时兼顾)
-
无法处理日志文件过大的问题(日志轮转)
-
2. 进阶用法:存到文件 + 自定义格式 + 日志轮转
在实际项目中,不会使用 basicConfig,而是通过配置 Logger 、Handler 和 Formatter 来实现专业日志。
-
Logger (日志器): 产生日志的对象,在代码中主要与它交互(如
logger.info())。 -
Handler (处理器): 决定日志的去向,比如输出到控制台 (
StreamHandler) 或文件 (FileHandler)。 -
Formatter (格式器): 定义日志的输出格式(如时间、级别、模块名等)。
python
import logging
# TimedRotatingFileHandler 用于按时间自动切割日志文件
# RotatingFileHandler 用于按大小自动切割日志文件
from logging.handlers import TimedRotatingFileHandler, RotatingFileHandler
# 1. 创建一个日志"器"(logger对象)
# __name__ 会使用当前模块的 Python 名称(例如 'my_module')
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG) # 设置日志器的总级别
# 2. 定义日志格式
formatter = logging.Formatter(
# asctime:时间;levelname:级别;module:模块名;lineno:行号;message:内容
"%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s"
)
# 3. 配置"控制台输出"处理器
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter) # 应用格式
logger.addHandler(console_handler) # 添加到日志器
# 4. 配置"文件输出"处理器(核心)
# TimedRotatingFileHandler:按时间轮转
file_handler = TimedRotatingFileHandler(
filename="app.log", # 日志文件名
when="D", # 轮转频率:D=天, H=小时, M=分钟
backupCount=7, # 保留7天的日志文件
encoding="utf-8" # 避免中文乱码
)
# file_handler = RotatingFileHandler(
# filename="app.log",
# # maxBytes: 单个日志文件的最大大小(字节)
# # 1024 * 1024 * 10 = 10MB (这里设置为 10MB 切割一次)
# maxBytes=10 * 1024 * 1024,
# backupCount=5, # 保留最近的 5 个文件
# encoding="utf-8"
# )
file_handler.setFormatter(formatter) # 应用格式
logger.addHandler(file_handler) # 添加到日志器
# 5. 测试日志输出
if __name__ == "__main__":
logger.info("服务启动成功,端口8000")
try:
1 / 0 # 故意制造错误
except Exception as e:
# exc_info=True 会自动打印完整的错误堆栈信息
logger.error(f"计算出错:{str(e)}", exc_info=True)
运行效果 (app.log 文件内容):
2.2 选项 2:第三方库 loguru (配置极简,开箱即用)
如果觉得 logging 配置太麻烦,强烈推荐使用 loguru。它 API 极简,一行代码就能实现文件输出、轮转和彩色日志。
1. 安装 loguru
bash
pip install loguru
2. 基础用法:一行配置搞定
loguru 的设计理念是"开箱即用",导入后直接使用 logger 对象。
python
# 1. 导入 loguru(不用复杂配置,直接用 logger 对象)
from loguru import logger
# 2. 配置日志存到文件(一行搞定!)
# sink:日志文件路径
# rotation:轮转规则(这里是按大小,500MB一个文件)
# retention:保留策略(保留10个文件)
logger.add(sink="app_loguru.log", rotation="500 MB", retention=10, encoding="utf-8")
# 3. 输出日志(用法和 logging 类似,但更直观)
logger.debug("调试信息:用户请求参数为{'name':'张三'}")
logger.info("正常信息:用户登录成功,ID=123")
logger.error("错误信息:数据库连接超时,地址=localhost:3306")
运行效果:
-
控制台 会显示彩色日志(DEBUG 蓝色、INFO 绿色、ERROR 红色)。
-
app_loguru.log 文件内容格式清晰:

3. 进阶用法:自定义格式 + 自动捕获异常
loguru 在捕获异常时也极其简单。
python
from loguru import logger
# 自定义日志格式(加模块名、行号)
logger.add(
sink="app_loguru2.log",
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {module}:{line} | {message}",
rotation="1 day", # 按天轮转
retention=7, # 保留7天
encoding="utf-8"
)
# 捕获异常(不用写 exc_info=True,直接用 exception 方法)
try:
1 / 0
except Exception as e:
# exception() 方法会自动打印完整的堆栈信息
logger.exception(f"计算错误:{str(e)}")
三、项目必守!5 条企业级日志规范
学会工具只是第一步,在项目中使用规范的日志才是关键。
规范 1:日志级别别乱用,按场景选对级别
不要所有日志都用 INFO 或 ERROR,这会导致关键错误被淹没。
| 级别 | 适用场景 | 例子 |
|---|---|---|
| DEBUG | 本地开发调试,上线后应关闭 | "变量 x 的值为 10","请求 URL:/api/login" |
| INFO | 项目正常运行的关键节点 | "服务启动成功","用户注册:手机号 138xxxx" |
| WARNING | 有潜在问题,但不影响当前功能 | "缓存过期,已自动刷新","内存使用率达 80%" |
| ERROR | 某个功能出错,但服务还能跑 | "用户张三登录失败:密码错误","订单创建失败" |
| CRITICAL | 致命错误,服务无法运行 | "数据库连接失败","端口 8000 被占用,服务启动失败" |
反面教材: 把"用户输入错误密码"标为
CRITICAL。------ 这是ERROR或WARNING级别的事件,服务并未崩溃。
规范 2:日志内容要含"三要素",拒绝模糊表述
糟糕的日志:"连接失败"、"登录出错"。
好的日志必须包含:时间(工具自动加)+ 具体场景 + 关键信息。
| 反面例子 | 正面例子(好的日志) |
|---|---|
| "连接失败" | "连接 MySQL 数据库失败,地址:localhost:3306,错误:超时" |
| "用户登录出错" | "用户登录失败,手机号:138xxxx,原因:密码错误" |
| "循环执行错了" | "处理订单循环出错,订单 ID:1001,错误:索引越界" |
秘诀: 日志应该能回答"什么时候、谁、做了什么、结果如何(或出了什么问题)"。
规范 3:日志文件"按规则命名 + 自动轮转"
不要把所有日志都堆在一个 log.txt 里,这会导致单个文件过大(几十 GB),难以打开和分析。
-
命名格式: 建议使用
项目名_日期.log(如shop_app_20240520.log)。 -
自动轮转: 必须配置日志轮转,避免占满磁盘。
-
按时间: 每天一个新文件 (如
rotation="1 day")。 -
按大小: 每个文件不超过 500MB (如
rotation="500 MB")。
-
-
日志清理: 必须配置保留策略,如保留 30 天内的日志 (如
retention=30)。
规范 4:敏感信息绝对不写进日志!
这是安全红线! 日志文件也可能被泄露,绝对不能包含:
-
密码、Token、API 密钥
-
用户手机号、身份证号、银行卡号
-
完整的数据库连接字符串
正确做法: 必须记录时,一定要用"*"脱敏。
错误:
logger.info(f"用户登录,用户名=admin,密码={password}")正确:
logger.info(f"用户登录,用户名=admin,密码=******")
规范 5:项目里统一配置日志,不要重复写
不要在每个 .py 文件里都写一遍日志配置。正确的做法是:
-
单独创建一个
logger_config.py文件,在里面完成所有logging或loguru的配置。 -
在其他模块中(如
main.py,db.py),只导入 这个配置好的logger对象来使用。
项目结构实例:
my_project/
├─ logger_config.py # 统一日志配置文件
├─ main.py # 主程序
└─ db.py # 数据库操作
logger_config.py (用 loguru 举例):
python
from loguru import logger
# 1. 移除 loguru 默认的控制台输出
logger.remove()
# 2. 统一配置"控制台"输出
logger.add(
sink=sys.stderr, # 输出到控制台
level="INFO", # 控制台只显示 INFO 及以上级别
format="{time:HH:mm:ss} | {level} | {message}"
)
# 3. 统一配置"文件"输出
logger.add(
sink="logs/shop_app_{time:YYYYMMDD}.log", # 日志文件路径
level="DEBUG", # 文件中记录 DEBUG 及以上所有级别
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {module}:{line} | {message}",
rotation="1 day",
retention=7,
encoding="utf-8"
)
# 4. 把 logger 导出,供其他模块使用
# (在 loguru 中,导入即可,无需显式导出)
main.py (导入使用):
python
# 从配置文件导入 logger,不用再配置
from logger_config import logger
def start_server():
logger.info("服务启动成功,端口8000") # 直接用
logger.debug("这是一个调试信息,只会出现在文件里")
if __name__ == "__main__":
start_server()
四、总结:新手该选哪个日志库?
-
想快速上手,功能够用: 选
loguru。配置简单,API 直观,彩色日志和异常捕获非常方便。 -
需要深度定制,或在严格限制第三方库的环境中: 选
logging。它是官方标准,功能最全,虽然配置复杂,但扩展性最强。
