Python Logging模块完全指南
针对编程小白的通俗易懂知识点汇总 – 告别print调试,掌握专业日志记录
为什么需要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(‘应用程序启动’)
核心知识点
最佳实践
- 使用模块名创建Logger:logger = logging.getLogger(__name__)
- 在主模块配置日志,其他模块只获取Logger
- 生产环境使用配置文件
- 为不同模块设置不同日志级别
- 使用RotatingFileHandler防止日志文件过大
常见错误
- 多次调用basicConfig() – 只有第一次生效
- 忘记设置日志级别 – 默认只显示WARNING及以上
- 在导入的模块中配置日志 – 应在主模块配置
- 日志格式不包含足够信息
- 忘记关闭文件Handler
高级功能
- 日志传播:子Logger的日志会传递给父Logger
- 捕获异常:logger.exception()自动记录异常信息
- 日志过滤:使用Filter类自定义过滤规则
- 日志轮转:RotatingFileHandler按大小/时间分割日志
- 网络日志:SocketHandler发送日志到网络
常用格式字段
- %(asctime)s – 日志时间
- %(name)s – Logger名称
- %(levelname)s – 日志级别
- %(message)s – 日志消息
- %(pathname)s – 完整路径
- %(filename)s – 文件名
- %(lineno)d – 行号
- %(funcName)s – 函数名
- %(thread)d – 线程ID
- %(process)d – 进程ID