日志记录在软件开发中扮演着至关重要的角色。它不仅可以帮助开发人员跟踪应用程序的状态和行为,还能提供有价值的诊断信息。Python 提供了内置的 logging 模块,为开发者提供了一个强大且灵活的日志记录工具。
1. 日志的重要性
在软件开发中,对于应用程序的行为进行监控和记录至关重要。日志记录不仅可以在应用程序出现错误时提供关键的调试信息,还能够帮助分析应用程序的性能、用户行为和其他重要数据。良好的日志策略是系统可观测性的基石。
本文详细阐述了 Python 中日志记录的核心概念与高级应用。内容涵盖日志级别定义、基础配置方法、自定义处理器与格式化器、配置文件管理(包括 dictConfig)、日志旋转策略以及过滤器使用。此外,文章补充了结构化日志(JSON 格式)的实现方式、Web 请求上下文信息的注入技巧,以及高并发场景下的异步日志处理方案。最后总结了生产环境中的日志最佳实践,包括安全性、性能优化及格式规范,旨在帮助开发者构建健壮、可观测的日志系统。

日志记录在软件开发中扮演着至关重要的角色。它不仅可以帮助开发人员跟踪应用程序的状态和行为,还能提供有价值的诊断信息。Python 提供了内置的 logging 模块,为开发者提供了一个强大且灵活的日志记录工具。
在软件开发中,对于应用程序的行为进行监控和记录至关重要。日志记录不仅可以在应用程序出现错误时提供关键的调试信息,还能够帮助分析应用程序的性能、用户行为和其他重要数据。良好的日志策略是系统可观测性的基石。
Python 的 logging 模块定义了五个标准级别,按严重程度递增排列:
默认情况下,日志级别为 WARNING,这意味着只有 WARNING 及以上级别的日志会被记录。可以通过设置根记录器的级别来调整。
logging 模块记录日志Python 的 logging 模块是一个功能强大且灵活的日志记录工具。下面是一个基本的配置和记录日志的示例:
import logging
# 配置基本日志格式和输出目标
logging.basicConfig(
level=logging.DEBUG,
filename='app.log',
filemode='w',
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# 创建日志记录器
logger = logging.getLogger('my_app')
# 记录不同级别的日志
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
logger.critical('This is a critical message')
以上示例演示了如何设置全局的日志级别、日志文件和格式化,并记录不同级别的日志信息。
日志格式化和处理器对于记录清晰和可读的日志非常重要。通过组合不同的处理器(Handler)和格式化器(Formatter),可以将日志输出到多个目的地(如控制台、文件、远程服务器)。
import logging
import sys
logger = logging.getLogger('advanced_app')
logger.setLevel(logging.DEBUG)
# 定义格式化器
formatter = logging.Formatter('%(asctime)s - %(name)s - [%(levelname)s] - %(message)s')
# 控制台处理器
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)
# 文件处理器
file_handler = logging.FileHandler('debug.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
# 添加处理器
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.debug('Debug message goes to both console and file')
logger.info('Info message goes to both console and file')
使用配置文件管理日志记录器配置是一种更为清晰和易于维护的方式。虽然可以使用 fileConfig,但在现代 Python 开发中,推荐使用 dictConfig 进行编程式配置,因为它更加灵活且无需依赖外部 .conf 文件。
import logging.config
LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
},
'json': {
'()': 'pythonjsonlogger.jsonlogger.JsonFormatter',
'fmt': '%(asctime)s %(name)s %(levelname)s %(message)s'
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'default',
'stream': 'ext://sys.stdout'
},
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'level': 'DEBUG',
'formatter': 'default',
'filename': 'app.log',
'maxBytes': 10485760, # 10MB
'backupCount': 5
}
},
'root': {
'level': 'DEBUG',
'handlers': ['console', 'file']
}
}
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger(__name__)
日志过滤器可以根据特定的条件来过滤和记录日志信息。以下是一个过滤器的简单示例,仅允许特定类型的消息通过:
class InfoFilter(logging.Filter):
def filter(self, record):
return record.levelno == logging.INFO
logger = logging.getLogger('filtered_app')
handler = logging.StreamHandler()
handler.addFilter(InfoFilter())
handler.setFormatter(logging.Formatter('%(message)s'))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.debug('This will be filtered out')
logger.info('This will appear in output')
logger.warning('This will be filtered out')
日志旋转是管理日志文件大小和数量的重要工具,防止日志文件无限增长占用磁盘空间。
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
# 基于大小的旋转
size_handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=5)
# 基于时间的旋转 (每天凌晨 0 点切割)
time_handler = TimedRotatingFileHandler('app.log', when='midnight', interval=1, backupCount=7)
在现代微服务架构中,结构化日志(如 JSON 格式)比纯文本更易被日志聚合系统(如 ELK Stack)解析。此外,在 Web 应用中,将请求 ID 注入日志上下文有助于追踪整个请求链路。
import json
import logging
class JsonFormatter(logging.Formatter):
def format(self, record):
log_record = {
'timestamp': self.formatTime(record),
'level': record.levelname,
'logger': record.name,
'message': record.getMessage(),
'extra': getattr(record, 'extra_data', {})
}
return json.dumps(log_record, ensure_ascii=False)
logger = logging.getLogger('structured')
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)
record = logger.makeRecord(logger.name, logging.INFO, '', 0, 'User login', (), None)
record.extra_data = {'user_id': 12345, 'ip': '192.168.1.1'}
logger.handle(record)
日志操作本身是线程安全的,但在高并发场景下,频繁的 I/O 操作可能成为瓶颈。建议在生产环境中使用异步日志处理(如 QueueHandler 和 QueueListener),将日志写入任务放入队列,由后台线程异步处理,从而减少主线程阻塞。
%s 延迟计算。优雅地处理日志对于应用程序的健康运行至关重要。logging 模块为开发者提供了多种方法来记录和管理日志信息。从基础的配置到高级的处理器、过滤器以及结构化日志,全面掌握这些技巧将显著提升系统的可维护性和可观测性。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online