为什么需要Logging模块?

当你的Python程序运行时,你可能想知道程序内部发生了什么:

  • 程序是否正常运行?
  • 出现了什么错误?
  • 用户执行了哪些操作?
  • 程序的性能如何?

停止使用print()调试!

虽然使用print()语句调试代码很方便,但在实际项目中存在很多问题:

  • 调试完成后需要删除或注释掉print语句
  • 输出信息杂乱,难以区分重要程度
  • 无法将日志输出到文件或其他地方
  • 生产环境中无法控制日志输出量

Logging模块提供了专业、灵活的日志记录解决方案。

日志级别:不同重要程度的消息

Logging模块将日志信息分为6个级别,重要性从低到高排列:

DEBUG (10)
INFO (20)
WARNING (30)
ERROR (40)
CRITICAL (50)

如何理解日志级别?

DEBUG: 最详细的日志信息,用于调试程序(如变量值、程序流程)

INFO: 确认程序按预期运行(如”用户登录成功”)

WARNING: 程序运行出现意外情况,但还能继续工作(如”磁盘空间不足”)

ERROR: 程序某些功能无法正常工作(如”文件打开失败”)

CRITICAL: 严重错误,程序可能无法继续运行(如”数据库连接丢失”)

💡 实际项目中,通常开发环境使用DEBUG级别,生产环境使用WARNING或更高级别。

Logging的四大核心组件

Logger(日志记录器)

应用程序直接使用的接口,用于记录日志消息。

每个Logger都有一个名称(如__name__),形成层级结构。

主要方法:debug(), info(), warning(), error(), critical()

Handler(处理器)

决定日志发送到哪里:

  • StreamHandler – 输出到控制台
  • FileHandler – 输出到文件
  • SMTPHandler – 发送邮件
  • HTTPHandler – 发送到Web服务器

Filter(过滤器)

决定哪些日志需要被记录(更精细的控制)

例如:只记录包含特定关键字的日志

可以附加到Logger或Handler上

Formatter(格式化器)

决定日志输出的格式:

  • 时间格式
  • 日志级别
  • 日志内容
  • 文件名和行号

使用类似:’%(asctime)s – %(name)s – %(levelname)s – %(message)s’

日志处理流程

1. 创建Logger对象并调用日志方法(如logger.info())

2. Logger检查日志级别是否满足要求

3. 创建LogRecord对象(包含所有日志信息)

4. 将LogRecord传递给所有注册的Handler

5. Handler使用Formatter格式化日志

6. Handler输出格式化后的日志到目标位置

三种配置方式

1. 基本配置(快速开始)

import logging # 基本配置(输出到控制台) logging.basicConfig( level=logging.DEBUG, format=’%(asctime)s – %(name)s – %(levelname)s – %(message)s’, datefmt=’%Y-%m-%d %H:%M:%S’ ) # 创建日志记录器 logger = logging.getLogger(__name__) # 记录日志 logger.debug(‘这是一条调试信息’) logger.info(‘程序启动’) logger.warning(‘磁盘空间不足’)

2. 配置文件(推荐方式)

# logging.conf 配置文件示例 [loggers] keys=root,sampleLogger [handlers] keys=consoleHandler,fileHandler [formatters] keys=simpleFormatter # 配置root logger [logger_root] level=DEBUG handlers=consoleHandler # 配置其他logger [logger_sampleLogger] level=DEBUG handlers=fileHandler qualname=sampleLogger propagate=0 # 配置handler [handler_consoleHandler] class=StreamHandler level=WARNING formatter=simpleFormatter args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=DEBUG formatter=simpleFormatter args=(‘app.log’, ‘a’) # 配置formatter [formatter_simpleFormatter] format=%(asctime)s – %(name)s – %(levelname)s – %(message)s datefmt=%Y-%m-%d %H:%M:%S

3. 字典配置(灵活方式)

import logging.config LOGGING_CONFIG = { ‘version’: 1, ‘formatters’: { ‘standard’: { ‘format’: ‘%(asctime)s – %(name)s – %(levelname)s – %(message)s’ } }, ‘handlers’: { ‘console’: { ‘class’: ‘logging.StreamHandler’, ‘formatter’: ‘standard’, ‘level’: ‘INFO’ }, ‘file’: { ‘class’: ‘logging.FileHandler’, ‘formatter’: ‘standard’, ‘level’: ‘DEBUG’, ‘filename’: ‘app.log’ } }, ‘loggers’: { ”: { # root logger ‘handlers’: [‘console’, ‘file’], ‘level’: ‘DEBUG’ }, ‘app.module’: { ‘handlers’: [‘file’], ‘level’: ‘INFO’, ‘propagate’: False # 阻止传递给父logger } } } # 应用配置 logging.config.dictConfig(LOGGING_CONFIG) # 使用日志记录器 logger = logging.getLogger(‘app.module’) logger.info(‘应用程序启动’)