前言
很多新手写 Python 代码调试的时候,习惯使用 print 函数打印信息。写小脚本的时候 print 简单方便,但一旦项目规模变大,print 的缺点就暴露无遗:无法区分日志级别,不能自动保存到文件,没有时间戳,不能过滤日志,上线之后没法关闭调试信息。Python 内置 logging 模块,专门用来处理日志,不需要额外安装第三方库,支持日志分级、文件输出、日志格式化、日志切割,是生产环境必备的工具。本文从基础使用到生产级配置,完整讲解 logging 模块,看完就可以直接用到项目中。
一、logging 基础概念:日志级别
logging 预定义了 5 个日志级别,优先级从低到高:DEBUG、INFO、WARNING、ERROR、CRITICAL。
- DEBUG:调试信息,开发阶段使用,打印变量、函数入参;
- INFO:普通运行信息,记录程序正常运行节点;
- WARNING:警告信息,程序可以继续运行,但存在潜在问题;
- ERROR:错误信息,部分功能执行失败;
- CRITICAL:严重错误,程序可能直接崩溃。
默认情况下 logging 的输出级别是 WARNING,DEBUG 和 INFO 的日志不会打印。我们先看最简单的示例:
import logging logging.debug("这是debug调试信息") logging.info("程序正常启动") logging.warning("警告:参数为空") logging.error("读取文件失败") logging.critical("程序致命错误")运行代码,控制台只会输出 warning、error、critical 日志。想要输出低级别日志,需要手动设置日志等级。
二、日志格式化与输出到文件
默认日志只有消息内容,缺少时间、日志级别、代码所在文件行号,排查问题很麻烦。我们可以自定义日志格式,同时让日志既输出控制台,又保存到本地日志文件。
import logging # 配置日志格式 log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' logging.basicConfig( level=logging.DEBUG, format=log_format, filename="app.log", filemode="a" # a追加写入,w覆盖写入 ) logging.info("服务启动成功") logging.debug("当前参数:test")%(asctime)s代表时间,%(levelname)s日志级别,%(message)s日志消息。但是 basicConfig 有局限性,当项目多模块导入时,容易出现日志重复打印问题,生产环境推荐使用 logger 对象的方式。
三、生产推荐写法:Logger、Handler、Formatter
logging 采用面向对象设计,核心组件:
- Logger:日志对象,对外调用 info/error 方法;
- Handler:处理器,控制日志输出到控制台还是文件;
- Formatter:格式化器,定义日志文本格式;
- Filter:过滤器,可以自定义过滤日志。
import logging # 创建logger实例 logger = logging.getLogger("my_project") logger.setLevel(logging.DEBUG) # 避免重复添加handler if not logger.handlers: # 控制台输出handler console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) # 文件handler file_handler = logging.FileHandler("app.log", encoding="utf-8") file_handler.setLevel(logging.INFO) # 格式化 fmt = logging.Formatter("%(asctime)s - %(filename)s:%(lineno)s - %(levelname)s - %(message)s") console_handler.setFormatter(fmt) file_handler.setFormatter(fmt) logger.addHandler(console_handler) logger.addHandler(file_handler) logger.info("项目启动") logger.error("数据库连接异常")这种写法可以实现:DEBUG 日志只在控制台打印,INFO 及以上级别保存到文件,分离不同渠道日志。
四、日志切割:防止日志文件无限变大
项目长时间运行,日志文件会持续增大,单个日志几个 G 的时候打开、读取都会很慢。logging 自带 RotatingFileHandler 按大小切割,TimedRotatingFileHandler 按时间切割。以按天切割为例:
from logging.handlers import TimedRotatingFileHandler # 每天生成一个日志文件,保留最近7天日志 time_handler = TimedRotatingFileHandler("app.log", when="D", interval=1, backupCount=7, encoding="utf-8") time_handler.setFormatter(fmt) logger.addHandler(time_handler)当达到设定时间,自动生成新日志文件,旧日志自动命名,超过 backupCount 自动删除过期日志,非常适合后台服务。
五、logging 常见坑点
- 多模块重复打印:多次 addHandler,每次 getLogger 都会新增处理器,增加判断
if not logger.handlers; - 编码问题:输出中文日志文件,必须指定 encoding="utf-8";
- 不要混用 basicConfig 和实例 logger,容易出现配置冲突;
- 异常捕获:记录异常堆栈可以使用
logger.exception("出错"),自动记录完整报错栈。
六、总结
print 适合临时调试小脚本,正式项目必须使用 logging。合理划分日志级别,线上环境把日志级别设置为 INFO,关闭 DEBUG 信息;配置日志切割,避免磁盘占满。这套日志配置可以直接复用在爬虫、后端接口、自动化脚本项目中。很多初学者写项目忽略日志,等到程序报错,没有任何记录,排查问题耗费大量时间。规范日志是工程化的第一步,后续会继续分享 Python 项目工程化最佳实践。