日志系统基础:Python logging模块详解
日志这东西,说白了就是给程序装个黑匣子。
我刚开始写Agent的时候,总觉得日志可有可无。代码跑得挺欢,加日志干嘛?直到有一次,我的Agent在凌晨三点突然抽风,返回了一堆莫名其妙的JSON。我盯着屏幕看了两个小时,愣是没找到问题在哪。嗯,从那以后,我再也不敢轻视日志了。
今天我们就来聊聊Python的logging模块。这是Python标准库自带的日志工具,功能强大,而且不用装任何第三方包。
日志级别:从DEBUG到CRITICAL
Python logging定义了五个日志级别。我习惯把它们想象成「警报的严重程度」:
| 级别 | 数值 | 什么时候用 |
|---|---|---|
| DEBUG | 10 | 调试信息,比如变量值、函数入口出口 |
| INFO | 20 | 正常操作信息,比如「任务开始」「请求成功」 |
| WARNING | 30 | 有问题但不影响运行,比如「API响应变慢」 |
| ERROR | 40 | 出错了,但程序还能继续跑 |
| CRITICAL | 50 | 严重错误,程序可能撑不住了 |
你想想看,如果所有信息都打印出来,日志文件会爆炸。所以我们要设置一个阈值。默认是WARNING,也就是说只有WARNING及以上级别的日志才会被输出。
核心原则:生产环境用INFO或WARNING,开发调试用DEBUG。别在生产环境开DEBUG,除非你想被日志刷屏刷到怀疑人生。
日志格式:让日志说话
光有日志内容还不够,格式也很重要。我见过最原始的日志就是一行字符串,连时间戳都没有。这种日志基本等于废纸。
一个合格的日志格式,至少应该包含:
- 时间戳:精确到毫秒,方便定位问题发生的时间点
- 日志级别:一眼看出严重程度
- 模块名:知道是哪个组件出的问题
- 具体消息:描述发生了什么
举个例子,我常用的格式是这样的:
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
输出效果:
2024-01-15 14:23:45,123 - agent.core - INFO - 任务调度器启动成功
你看,一行日志就把「什么时候、谁、什么级别、什么事」说清楚了。
小技巧:在Agent项目中,我习惯把%(name)s设置成模块的完整路径,比如agent.plugins.weather。这样日志一出来,我就能知道是哪个插件在说话。
日志处理器:日志该去哪
日志处理器(Handler)决定了日志的「目的地」。你可以把日志送到:
- 控制台(StreamHandler)
- 文件(FileHandler)
- 网络(SocketHandler)
- 邮件(SMTPHandler)
- 甚至HTTP接口(HTTPHandler)
我一般会同时配两个处理器:一个输出到控制台,方便开发时实时查看;一个写入文件,方便事后排查。
import logging
# 创建logger
logger = logging.getLogger('agent.core')
logger.setLevel(logging.DEBUG)
# 控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 文件处理器
file_handler = logging.FileHandler('agent.log')
file_handler.setLevel(logging.DEBUG)
# 设置格式
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 添加处理器
logger.addHandler(console_handler)
logger.addHandler(file_handler)
这段代码的意思是:控制台只显示INFO及以上级别的日志,但文件里会记录所有DEBUG级别的信息。这样既不会刷屏,又保留了完整的调试信息。
注意:我曾经犯过一个错误——给同一个logger重复添加了两次文件处理器。结果每条日志都写了两遍,日志文件膨胀得飞快。所以记得检查一下,别重复添加。
知识体系:一张图说清楚
下面这张图展示了logging模块的核心组件和它们之间的关系:
这张图的核心逻辑很简单:Logger接收日志消息,经过级别过滤后,交给Handler。Handler再根据配置的Formatter,把日志写到指定的地方。
实战建议:Agent项目中的日志配置
在Agent项目中,我一般会这样配置日志:
- 每个模块一个独立的Logger:比如
agent.planner、agent.executor、agent.memory。这样日志里能清楚看到是哪个模块在干活。 - 日志文件按天滚动:用
TimedRotatingFileHandler,每天生成一个新文件。避免单个日志文件太大。 - 敏感信息脱敏:API Key、用户密码这些,绝对不能出现在日志里。我习惯写一个自定义的Formatter,自动过滤掉敏感字段。
- 结构化日志:对于Agent的决策过程,我建议用JSON格式记录。比如:
{"action": "call_tool", "tool": "search", "query": "天气", "result": "..."}。这样后续分析起来特别方便。
个人经验:我习惯在Agent的每个关键决策点都打一条INFO日志。比如「选择了哪个工具」「返回了什么结果」。这样出了问题,我只要看日志就能还原Agent的思考过程,比猜来猜去高效多了。
好了,日志系统的基础就聊到这。记住一句话:日志不是写给机器看的,是写给未来的你(或者你的同事)看的。把日志写清楚,就是给自己留条后路。
公众号:蓝海资料掘金营,微信deep3321