
Python项目的日志管理,核心在于有效利用标准库
logging
要进行Python项目的日志管理,我们通常会围绕
logging
logging.info("Something happened")logging.getLogger(__name__)
logger.setLevel(logging.INFO)
StreamHandler
sys.stdout
sys.stderr
FileHandler
RotatingFileHandler
TimedRotatingFileHandler
SMTPHandler
HTTPHandler
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
一个典型的日志配置代码片段可能会是这样:
import logging
from logging.handlers import RotatingFileHandler
import os
# 定义日志文件路径
log_dir = "logs"
os.makedirs(log_dir, exist_ok=True)
log_file_path = os.path.join(log_dir, "my_application.log")
# 1. 获取Logger实例
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG) # 设置Logger的最低处理级别
# 2. 创建一个Formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(funcName)s - %(lineno)d - %(message)s'
)
# 3. 创建StreamHandler(输出到控制台)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO) # 控制台只显示INFO及以上级别
console_handler.setFormatter(formatter)
# 4. 创建RotatingFileHandler(输出到文件,文件大小限制10MB,保留5个备份)
file_handler = RotatingFileHandler(
log_file_path,
maxBytes=10 * 1024 * 1024, # 10 MB
backupCount=5,
encoding='utf-8'
)
file_handler.setLevel(logging.DEBUG) # 文件记录所有DEBUG及以上级别
file_handler.setFormatter(formatter)
# 5. 将Handler添加到Logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# 示例使用
logger.debug("这是一个调试信息")
logger.info("程序启动,加载配置...")
logger.warning("发现潜在问题:配置项缺失")
try:
1 / 0
except ZeroDivisionError:
logger.error("发生严重错误:除零异常", exc_info=True) # exc_info=True 会记录异常堆栈通过这种方式,我们可以灵活地控制哪些日志输出到哪里,以何种格式输出。这使得日志管理变得有条不紊,而不是杂乱无章。
立即学习“Python免费学习笔记(深入)”;
在实际开发中,我们很少能用一套固定的日志配置打天下。开发环境可能需要输出详尽的DEBUG信息到控制台,方便快速调试;而生产环境则更倾向于将INFO及以上级别的日志写入文件,并可能发送到中央日志系统,同时严格控制日志量以节省资源。这就引出了日志配置的动态化需求。
我个人比较推荐使用基于字典的配置(
logging.config.dictConfig
基于dictConfig
这是一种非常强大且灵活的方式。你可以将整个日志配置写成一个Python字典,然后传递给
logging.config.dictConfig
import logging.config
import yaml # 或者 json
# 假设这是一个 YAML 配置文件内容
LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False, # 禁用已存在的logger,通常设为False
'formatters': {
'standard': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
},
'verbose': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s'
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'standard',
'stream': 'ext://sys.stdout'
},
'file_dev': {
'class': 'logging.handlers.RotatingFileHandler',
'level': 'DEBUG',
'formatter': 'verbose',
'filename': 'logs/app_dev.log',
'maxBytes': 1048576, # 1MB
'backupCount': 3,
},
'file_prod': {
'class': 'logging.handlers.RotatingFileHandler',
'level': 'INFO',
'formatter': 'standard',
'filename': 'logs/app_prod.log',
'maxBytes': 10485760, # 10MB
'backupCount': 5,
}
},
'loggers': {
'my_app': { # 你的应用主Logger
'handlers': ['console', 'file_dev'], # 开发环境使用
'level': 'DEBUG',
'propagate': False # 不向父级Logger传递日志
},
'another_module': {
'handlers': ['file_prod'],
'level': 'WARNING',
'propagate': False
}
},
'root': { # 根Logger,通常作为所有未显式配置Logger的兜底
'handlers': ['console'],
'level': 'WARNING'
}
}
# 在应用启动时加载配置
# logging.config.dictConfig(LOGGING_CONFIG)
# 动态切换环境的例子
ENV = os.environ.get('APP_ENV', 'development') # 从环境变量获取当前环境
if ENV == 'production':
LOGGING_CONFIG['loggers']['my_app']['handlers'] = ['console', 'file_prod']
LOGGING_CONFIG['loggers']['my_app']['level'] = 'INFO'
# 生产环境可能还需要额外的Handler,比如发送到中央日志系统
# LOGGING_CONFIG['handlers']['remote'] = {...}
# LOGGING_CONFIG['loggers']['my_app']['handlers'].append('remote')
elif ENV == 'development':
LOGGING_CONFIG['loggers']['my_app']['handlers'] = ['console', 'file_dev']
LOGGING_CONFIG['loggers']['my_app']['level'] = 'DEBUG'
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger('my_app')
logger.debug("这条消息只在开发环境显示")
logger.info("这条消息在所有环境都显示")通过环境变量(如
APP_ENV
生产环境的日志管理远比开发调试复杂,它面临着性能、可靠性、可观测性等多方面的挑战。我曾遇到过日志文件撑爆磁盘导致服务崩溃的惨痛经历,也为在海量日志中定位一个偶发问题而抓狂。
常见挑战:
应对策略:
RotatingFileHandler
TimedRotatingFileHandler
logrotate
SocketHandler
HTTPHandler
logging.handlers.QueueHandler
logging.handlers.QueueListener
***
Formatter
Filter
INFO
WARNING
sys.excepthook
ERROR
CRITICAL
这些策略的组合使用,能让生产环境的日志管理变得更加健壮和高效。
仅仅记录日志是不够的,日志的真正价值在于分析。但传统的纯文本日志,虽然人类阅读起来直观,机器解析起来却异常困难。这就是为什么结构化日志变得越来越重要。
结构化日志 (Structured Logging):
结构化日志的核心思想是将日志消息表示为机器可读的数据格式,通常是JSON。而不是一个长长的字符串,日志消息会包含一系列键值对,每个键代表一个特定的上下文信息。
为什么需要结构化日志?
user_id
123
event_type
payment_failed
如何实现结构化日志?
最直接的方式是使用一个专门的库,比如
python-json-logger
logging.Formatter
import logging
import logging.config
import json_log_formatter # pip install python-json-logger
# 定义一个自定义的JSON Formatter
class CustomJsonFormatter(json_log_formatter.JsonFormatter):
def add_fields(self, log_record, message_dict):
super(CustomJsonFormatter, self).add_fields(log_record, message_dict)
# 添加自定义字段
message_dict['service'] = 'my_awesome_service'
message_dict['version'] = '1.0.0'
# 如果有request_id或user_id,也可以从线程局部存储中获取
# message_dict['request_id'] = getattr(threading.current_thread(), 'request_id', 'N/A')
# 示例配置
LOGGING_CONFIG_JSON = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'json': {
'()': CustomJsonFormatter, # 使用自定义的JSON Formatter
'format': '(levelname) (name) (message)' # 这个format字符串实际上会被json_log_formatter忽略,但必须存在
}
},
'handlers': {
'json_console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'json',
'stream': 'ext://sys.stdout'
},
'json_file': {
'class': 'logging.handlers.RotatingFileHandler',
'level': 'DEBUG',
'formatter': 'json',
'filename': 'logs/app_structured.log',
'maxBytes': 1048576,
'backupCount': 3,
}
},
'loggers': {
'my_app_json': {
'handlers': ['json_console', 'json_file'],
'level': 'DEBUG',
'propagate': False
}
},
'root': {
'handlers': ['json_console'],
'level': 'WARNING'
}
}
logging.config.dictConfig(LOGGING_CONFIG_JSON)
json_logger = logging.getLogger('my_app_json')
json_logger.info("用户登录成功", extra={'user_id': 123, 'ip_address': '192.168.1.100'})
json_logger.warning("数据库连接超时", extra={'db_host': 'localhost', 'port': 5432})
try:
result = 1 / 0
except ZeroDivisionError:
json_logger.error("计算失败", exc_info=True, extra={'operation': 'division'})在上面的例子中,
extra
日志分析:
一旦日志被结构化并收集到中央日志系统(如ELK),分析就变得非常直观:
level:ERROR AND user_id:123
从我个人的经验来看,从纯文本日志转向结构化日志,再配合一套强大的集中式日志系统,是提升生产环境可观测性和问题排查效率的关键一步。它将日志从“一堆文件”变成了“可查询、可分析的数据”,极大地赋能了运维和开发团队。
以上就是如何进行Python项目的日志管理?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号