日志框架选型:Python logging模块深度解析、Loguru库实战、结构化日志与文本日志对比
日志这东西,平时没人关注,一出事它就是救命稻草。我在量化交易系统运维这行干了快十年,见过太多因为日志没配好,排查故障花了一整夜的惨案。今天咱们就聊聊Python世界里几个主流的日志框架,以及它们在实际交易系统里的用法。
Python内置logging模块:老牌劲旅
Python自带的logging模块,说实话,功能很全。但它的配置方式,嗯…有点反人类。我记得刚入行那会儿,第一次配logging,光看文档就花了两小时。
它的核心组件就四个:Logger、Handler、Formatter、Filter。说白了就是:谁在记、记到哪、怎么记、记什么。
核心要点:logging模块的配置方式有两种——基本配置和字典配置。生产环境我强烈建议用字典配置,灵活得多。
import logging
import logging.config
# 字典配置示例
LOGGING_CONFIG = {
'version': 1,
'formatters': {
'default': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'default'
},
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'trade_system.log',
'maxBytes': 10485760, # 10MB
'backupCount': 5,
'level': 'DEBUG'
}
},
'root': {
'level': 'DEBUG',
'handlers': ['console', 'file']
}
}
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger(__name__)
这里有个坑,我踩过好几次。RotatingFileHandler的备份文件数量,别设太大。我曾经设了50个,结果磁盘爆了。交易系统日志量很大的,一天几个GB很正常。
注意:logging模块的线程安全是没问题的,但多进程环境下要小心。每个进程都会写同一个文件,会乱。解决方案是用QueueHandler+QueueListener,或者干脆用第三方库。
Loguru库:优雅的替代方案
说实话,我第一次用Loguru的时候,感觉就是「这才对嘛」。它把logging那些繁琐的配置全简化了。你想想看,一行代码就能搞定日志初始化,多爽。
from loguru import logger
# 一行配置
logger.add("trade_{time}.log", rotation="500 MB", retention="10 days", level="DEBUG")
# 使用起来更简单
logger.info("订单已提交,订单ID: {}", order_id)
logger.debug("行情数据: {}", market_data)
logger.error("交易执行失败: {}", exc_info=True)
Loguru最让我喜欢的是它的格式化能力。用{}占位符,不用再写%s了。而且它自动捕获异常堆栈,不用手动传exc_info。
我在一个高频交易项目里用过Loguru。当时需要记录每个订单的完整生命周期,从生成到成交。用Loguru的bind方法,可以给每条日志绑定上下文信息,比如订单ID、策略ID。排查问题时,按订单ID一搜,整个链路就出来了。
# 绑定上下文
logger = logger.bind(order_id="ORD20240321001", strategy="momentum_v2")
logger.info("订单创建")
logger.info("订单发送至交易所")
logger.info("订单部分成交")
小技巧:Loguru的rotation参数支持按时间、按大小轮转。我习惯用"00:00"每天切一次,配合retention保留7天。这样日志文件不会太大,查找也方便。
结构化日志 vs 文本日志
这个问题,说白了就是「人看的」和「机器看的」的区别。文本日志适合人眼扫读,结构化日志适合程序分析。
在量化交易系统里,我强烈推荐结构化日志。为什么?因为交易日志量太大了,你不可能一条条看。得用ELK或者Splunk这类工具去分析。而结构化日志,比如JSON格式,天生就是给这些工具吃的。
| 对比维度 | 文本日志 | 结构化日志(JSON) |
|---|---|---|
| 可读性 | 高,人眼直接看 | 低,需要格式化 |
| 解析效率 | 低,需要正则匹配 | 高,直接解析JSON |
| 查询能力 | 弱,只能全文搜索 | 强,可按字段过滤 |
| 存储空间 | 小 | 大(约多30%) |
| 适用场景 | 开发调试、小规模系统 | 生产环境、大规模系统 |
来看看实际对比。同样的交易日志,文本格式长这样:
2024-03-21 14:30:01,234 - trade_executor - INFO - 订单成交: 订单ID=ORD20240321001, 价格=123.45, 数量=1000, 方向=买入
JSON格式长这样:
{
"timestamp": "2024-03-21T14:30:01.234",
"logger": "trade_executor",
"level": "INFO",
"message": "订单成交",
"order_id": "ORD20240321001",
"price": 123.45,
"quantity": 1000,
"direction": "买入"
}
你看,JSON格式多了字段名,占空间,但查询起来太方便了。在Kibana里直接搜order_id: ORD20240321001,所有相关日志秒出。
我的建议:开发环境用文本日志,方便调试。生产环境用JSON格式,方便分析。用Loguru的话,切换格式就是改一行配置的事。
实战:用Loguru输出结构化日志
下面是我在一个实盘交易系统里用的配置。它同时输出文本日志(给运维看)和JSON日志(给分析系统吃)。
from loguru import logger
import sys
# 移除默认的handler
logger.remove()
# 控制台输出:文本格式,带颜色
logger.add(
sys.stdout,
format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level:<8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
level="INFO",
colorize=True
)
# 文件输出:JSON格式,按天轮转
logger.add(
"logs/trade_{time:YYYY-MM-DD}.json",
format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {extra[order_id]} | {message}",
serialize=True, # 输出JSON格式
rotation="00:00",
retention="7 days",
level="DEBUG",
enqueue=True # 线程安全
)
# 使用示例
logger.bind(order_id="ORD001").info("订单创建")
logger.bind(order_id="ORD001").info("订单发送成功")
这里有个细节,enqueue=True这个参数。它让日志写入变成异步的,不会阻塞主线程。在高频交易场景下,这个很重要。我曾经见过因为日志I/O阻塞导致订单延迟的案例,那叫一个惨。
知识体系总览
下面这张图,是我对日志框架选型的理解。它涵盖了从基础组件到生产实践的完整链路。
这张图把今天讲的内容串起来了。从框架选型开始,到具体实现,再到输出格式的选择。你想想看,一个完整的日志体系,其实就是这几个环节的组合。
最后说一句:日志框架没有银弹。logging模块功能全但配置繁琐,Loguru简单优雅但灵活性稍差。我的建议是:小项目用Loguru,大项目用logging+结构化日志。关键是要形成规范,团队统一,别今天用这个明天换那个。
公众号:蓝海资料掘金营,微信deep3321