← 全部文章

日志有什么用?

写给 vibe coder 的指南。

客户打来电话。他昨天下了单,也付了款,可确认邮件始终没收到。他想知道这个订单到底存不存在。

你打开后台。订单在:编号 4521,已付款,备货中。你告诉他没问题,一切正常,马上给他重发一封邮件。客户放心了。他并不关心邮件为什么没到。

你关心。因为如果他遇到了,别人多半也遇到了,明天就会有下一个人打来电话。后台不会告诉你原因:它展示的是事物当前的状态,而不是发生过什么。

于是你打开日志,搜索 4521,事情的经过就出现了:订单已保存,付款已确认,系统调用了邮件服务,邮件服务返回 429 Too Many Requests:已达到每日上限。邮件根本没有发出去。你的代码把这个错误记了下来,然后若无其事地继续往下走。没有人重试,也没有人通知你。

再搜索 429,又冒出二十三条,全都是从订单 4512 开始的。那天生意很好,而邮件服务商的免费套餐有每日上限。现在你知道发生了什么,影响了哪些人,该修什么:把发信放进队列,等额度重置后重试,或者换一个套餐。三十秒。

现在想象一下没有日志的情形。订单在后台里,邮件没送到,除此之外你一无所有。你会怎么办?把流程再跑一遍,看它会不会重现?去问写这段代码的智能体?如果它手里只有代码,它会去读代码,然后告诉你本来应该发生什么。至于实际发生了什么,它毫无头绪。谁都没有。你只能猜。

差别就在这里。代码说的是程序一般会怎么做,日志说的是它那一次做了什么。

而且不一定要你自己去读。只要日志在,你就可以把它交给智能体,让它查一查订单 4521 到底怎么了。有了证据摆在面前,智能体就不用再猜:它会找到那条 429,数出另外二十三条,并建议你加上重试。变的不是智能体,而是它手边有什么。

为什么光写进文件还不够

要知道程序做了什么,最简单的办法是让它自己写下来:在代码里加一行,把"我走到这里了"或"这个值是多少"记进文件。有个程序员遇到一个在自己电脑上复现不了的错误,做的就是这件事:把代码传到服务器上,等着错误再次出现。

这办法管用,直到它不管用。文件越写越大,最后把磁盘写满,服务器也随之宕机。每一步都写磁盘,程序会变慢。每个程序员各记各的格式,谁也看不懂别人的。所以才有了日志库:日志级别(这是错误,这只是普通信息)、文件滚动、后台异步写入、统一的格式。今天你用的任何一个日志库,解决的都是这些老问题。

接下来才是真正重要的想法:不要等客户打电话来。如果日志里已经写着邮件发送失败,系统可以当场就提醒你,而不是三天以后。日志不再只是出了问题才去翻的东西,它会反过来告诉你出问题了。

今天,没有日志的正经系统已经不存在了。日志太寻常,以至于没人再去想它到底是干什么用的。

为什么叫"日志"

中文里的"日志",字面意思是"按日期记下来的记录":日是一天,志是记载。轮船上的"航海日志"就是这样一本簿子,值班的船员每天把航向、天气和航速写进去。英文里的 log 走的是另一条路:它原本指的是一块木头。电子计算机出现之前,水手把一块木片系在一根打了结的绳子上,抛进海里,再数半分钟里有几个绳结从手里滑过去,由此量出船速。这就是"节"(knot)成为航速单位的由来。量出的数字被记进 logbook,也就是我们说的航海日志,连同航向、时间和天气,让任何人事后都能还原整趟航程。后来,程序员把程序运行时做过的事写进文件,借用了同一个名字,中文便把它翻成现成的"日志"。两条线索在这里汇合:英文留下的是那块木头,中文留下的是那本按天写的簿子;但说的是同一件事——为日后翻看而留下的、关于"发生过什么"的记录。

有了智能体,什么没有变

如果你的应用是智能体写的,上面说的一切都不会消失。网络照样会出故障,邮件服务照样会变慢,支付服务商照样会在重试来得不巧的时候扣两次款。这些都与代码是谁写的无关,智能体自己也免不了犯错。不同之处在别的地方。

以前出了问题,你就打开代码去读。现在代码是智能体写的,多到一个人读不完,而且越来越少有人去读。很多人已经不再审查智能体生成的代码,只看它能不能跑。可是,没读过代码是一回事,不知道代码运行时做了什么,则是另一回事。

你和"实际发生了什么"之间的距离变长了。以前有个程序员,记得自己写了什么、为什么这么写。现在只有一个对上一次会话毫无记忆的智能体,和一堆没人完整读过的代码。夹在中间、唯一留下来的就是日志。日志在,而且智能体查得到,你就知道发生了什么;日志不在,你去问它,它会信心十足地告诉你本来应该发生什么。

日志的用处也不止于查错:你可以用它分析用户在你的应用里做了什么,也可以留下系统在何时做了什么的凭据,以备日后有人追问。不过这些都是水到渠成的事,前提是日志先得存在。

该怎么做

检验的办法就是你自己的订单 4521:随便挑一个昨天的订单,让智能体还原它经历了什么。不是看代码,而是看实际发生的事。如果它能把整个过程讲清楚——调用了什么、结果如何、花了多久——说明你有日志,而且智能体查得到。如果讲不出来,就是两样里缺了一样:要么日志根本没有,要么有,但智能体够不着。这两种情况都能解决。

如果没有日志,就让智能体把每个重要步骤都记下来:调用了什么、结果如何、花了多久,以及对应的是哪个订单。最后这一项,是上面整个例子能成立的关键。写完以后要检查一下它是不是真的记了,因为当衡量标准只有"代码能不能跑"的时候,这恰恰是最先被漏掉的。

等客户打来电话的时候——他一定会打来——希望你手里有东西可看,你的智能体也一样。

通过 RSS 订阅