Python logging模块从入门到精通:告别print,构建专业日志系统

📅 2026/7/31 5:31:11
Python logging模块从入门到精通:告别print,构建专业日志系统
在Python开发中很多初学者习惯用print()来调试和记录程序运行状态。但当你进入生产环境或者项目规模变大时print()的局限性就完全暴露出来了❌ 无法区分日志的重要程度❌ 不能灵活控制输出开发环境输出全部生产环境只输出错误❌ 无法将日志持久化保存到文件❌ 多模块项目中难以追踪日志来源❌ 不能按时间或大小自动分割日志文件今天我将带你全面掌握Python标准库中的logging模块从最基础的概念到实际项目中的应用让你彻底告别print()一、logging模块快速入门1.1 最简单的使用方式import logging # 配置基础日志设置 logging.basicConfig(levellogging.DEBUG) # 记录不同级别的日志 logging.debug(这是debug级别的日志) logging.info(这是info级别的日志) logging.warning(这是warning级别的日志) logging.error(这是error级别的日志) logging.critical(这是critical级别的日志)1.2 日志级别详解logging模块定义了5个标准日志级别从低到高级别数值使用场景DEBUG10详细的调试信息只在开发阶段使用INFO20程序正常运行的关键节点信息WARNING30程序仍能运行但需要注意的异常情况ERROR40程序某些功能无法执行但整体未崩溃CRITICAL50严重错误程序可能无法继续运行import logging # 设置日志级别为WARNING logging.basicConfig(levellogging.WARNING) # DEBUG和INFO级别低于WARNING不会输出 logging.debug(这条不会显示) logging.info(这条也不会显示) # WARNING及以上级别会输出 logging.warning(这条会显示) # 输出 logging.error(这条会显示) # 输出 logging.critical(这条会显示) # 输出二、配置日志格式2.1 自定义日志格式默认的日志格式不够友好我们可以自定义格式import logging logging.basicConfig( levellogging.DEBUG, format%(asctime)s - %(levelname)s - %(message)s, datefmt%Y-%m-%d %H:%M:%S ) logging.info(程序启动成功) logging.warning(磁盘空间不足) 2026-07-30 15:30:45 - INFO - 程序启动成功 2026-07-30 15:30:45 - WARNING - 磁盘空间不足2.2 常用格式化字段字段说明示例值%(asctime)s日志记录时间2026-07-30 15:30:45%(levelname)s日志级别名称INFO%(message)s日志消息内容程序启动成功%(name)s日志记录器名称root%(filename)s文件名main.py%(lineno)d行号25%(funcName)s函数名main%(process)d进程ID12345%(thread)d线程ID67890%(pathname)s文件完整路径/app/main.py%(module)s模块名main%(created)f创建时间戳浮点数1681234567.892.3 生产环境推荐的格式import logging logging.basicConfig( levellogging.INFO, format[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s, datefmt%Y-%m-%d %H:%M:%S ) def process_data(): logging.info(开始处理数据) logging.warning(数据量超过阈值) process_data() [2026-07-30 15:30:45] [INFO] [main.py:12] 开始处理数据 [2026-07-30 15:30:45] [WARNING] [main.py:13] 数据量超过阈值三、日志输出到文件3.1 基础文件输出import logging logging.basicConfig( levellogging.DEBUG, format%(asctime)s - %(levelname)s - %(message)s, datefmt%Y-%m-%d %H:%M:%S, filenameapp.log, # 指定日志文件 filemodew # w覆盖写入a追加默认 ) logging.info(程序启动) logging.error(发生错误) logging.info(程序结束) 2026-07-30 15:30:45 - INFO - 程序启动 2026-07-30 15:30:45 - ERROR - 发生错误 2026-07-30 15:30:45 - INFO - 程序结束3.2 同时输出到控制台和文件import logging # 创建日志记录器 logger logging.getLogger(my_app) logger.setLevel(logging.DEBUG) # 创建控制台处理器 console_handler logging.StreamHandler() console_handler.setLevel(logging.INFO) # 创建文件处理器 file_handler logging.FileHandler(app.log, encodingutf-8) file_handler.setLevel(logging.DEBUG) # 设置日志格式 formatter logging.Formatter( %(asctime)s - %(levelname)s - %(message)s, datefmt%Y-%m-%d %H:%M:%S ) console_handler.setFormatter(formatter) file_handler.setFormatter(formatter) # 添加处理器到日志记录器 logger.addHandler(console_handler) logger.addHandler(file_handler) # 使用日志 logger.debug(调试信息只在文件中有) logger.info(普通信息控制台和文件都有) logger.warning(警告信息控制台和文件都有) logger.error(错误信息控制台和文件都有)输出效果控制台显示INFO及以上级别的日志文件显示DEBUG及以上级别的所有日志四、Logger对象的使用4.1 为什么使用Logger对象在前面的例子中我们直接使用logging.info()等函数这实际上使用的是根日志记录器root logger。但在大型项目中我们通常为每个模块创建独立的Logger对象以便更好地控制日志。4.2 创建和使用Loggerimport logging # 创建名为 my_module 的日志记录器 logger logging.getLogger(my_module) logger.setLevel(logging.DEBUG) # 添加处理器 handler logging.StreamHandler() handler.setLevel(logging.DEBUG) formatter logging.Formatter(%(name)s - %(levelname)s - %(message)s) handler.setFormatter(formatter) logger.addHandler(handler) # 使用Logger logger.debug(调试信息) logger.info(普通信息) logger.warning(警告信息) my_module - DEBUG - 调试信息 my_module - INFO - 普通信息 my_module - WARNING - 警告信息4.3 使用__name__的最佳实践在Python中推荐使用__name__作为Logger的名称# 在 mymodule.py 中 import logging logger logging.getLogger(__name__) # 使用 __name__ def do_something(): logger.info(执行某个操作) try: # 业务代码 pass except Exception as e: logger.error(f操作失败{e})为什么使用__name____name__会自动反映模块的完整导入路径例如mypackage.mymodule这样你可以针对不同包设置不同的日志级别4.4 日志传播机制Logger之间存在层级关系子Logger的日志默认会向上传播给父Logger。import logging # 创建父Logger parent logging.getLogger(parent) parent.setLevel(logging.INFO) handler logging.StreamHandler() handler.setFormatter(logging.Formatter(%(name)s - %(message)s)) parent.addHandler(handler) # 创建子Logger child logging.getLogger(parent.child) child.setLevel(logging.DEBUG) # 子Logger的日志会传播到父Logger child.info(这条信息会显示) # 父Logger会处理 child.debug(调试信息不会显示) # 父Logger级别是INFO不会显示 # 阻止传播 child.propagate False child.info(这条信息只由自己处理不会传播到父Logger)