讲真,我看到这篇技术文章的第一反应是——不是我说,你们这些AI工具搞出来的日志文件是真的又怂又贪。怂在哪?怂在它们不声不响,连个通知都不给你发,就默默在那吃空间。贪在哪?贪在一个叫agentmemory.err.log的家伙,一周就能飙到5.3MB——就一个星期!你这辈子写过的情书加起来都没它多。
好了,我是kisa吐槽大王,今天不骂人,我们来聊聊一个看起来很技术、但本质上跟"你钱包里莫名其妙少了几百块"一样闹心的问题:你的AI助手日志,正在偷偷吃掉你的硬盘。
---
先说说这个"坑"有多离谱
原文作者Lily干了件挺聪明的事。她发现~/.claude/logs/这个目录不太对劲——不是她主动去看的,而是某天系统出了问题她才去翻,结果发现文件已经堆到了20MB。20MB放在今天可能不算什么,但你想想,这是纯文本啊兄弟。虽然严格来说纯文本日志写到20MB也不算天量(我知道有人见过几百MB的文本日志),但在没有任何轮转机制、纯靠手动管理的前提下让它自由生长到20MB,已经很离谱了。
更骚的是什么呢?hook-latency.jsonl和vault-auto-ingest.log这两个文件,在同一周双双突破5MB。不是你一个在胖,是大家一起胖,整得跟集体吃自助餐似的。
问题在于: 一般的日志轮转方案(logrotate)不顶用。因为你的监控脚本正用tail -f拽着日志文件不放手,logrotate默认操作是"把旧文件改名成.1,然后新建一个文件"——结果你的监控脚本还盯着旧文件的inode(文件系统里的身份证号),但AI工具的其他脚本是按文件路径找的,路径指向了新文件,新文件里啥也没有。于是你的日志系统就精神分裂了:监控说"我有数据",AI脚本说"日志是空的"。
这设计,也是绝了。
---
那她是怎么破的?学习路径来了
现在的重点是:你要是也想解决这个问题,该怎么学、怎么用?
别慌,我帮你们把这个过程拆开,顺便吐吐槽。
第一步:理解"文件路径不能变"这个硬约束
作者的做法很直接:不要换文件,只裁内容。
具体就三行命令:
bash
MAX_BYTES=$((5 1024 1024))
KEEP_LINES=2000
tail -n "$KEEP_LINES" "$f" > "$f.tmp" && mv "$f.tmp" "$f"
注意这里有三个关键点:
1. 为什么用tail -n 2000 > 临时文件再mv覆盖,而不是直接重定向到原文件? 因为如果你直接写> "$f",万一脚本在写入中间崩了,原文件就变成空文件了——你宝贵的日志全没了。而用临时文件+mv,mv是原子操作(要么全换,要么不换),安全性高很多。顺便说一句,这里mv替换文件后inode确实会变,但因为监控脚本按文件路径重新打开文件,路径没变它们就能看到新内容,inode变不变根本不影响方案的有效性,不用纠结。
2. 为什么要保留下2000行? 因为日志嘛,最关心的是最近的记录。历史数据?谁在乎。你又不是写自传。
3. 为什么作者没用logrotate的copytruncate选项? 它的逻辑是"先复制,再截断原文件",但如果你运气不好,在复制和截断之间那几秒有大量日志写入,这几秒的内容就永远丢了。tail + mv不存在这个时间窗口,所以更安全。
~/.bash_history或者某个程序的*.log),手动执行一遍上面的命令,看看效果。不要一上来就搞自动化,先手动确认没毛病。
第二步:定时执行,但别让它半夜吵到你
作者用macOS的launchd做定时任务,每天凌晨3:45跑一次。这个时间点选择很有讲究——因为她的AI自动任务(autopilot)5点开始,所以赶在它前面做完日志清理。
但这里有个坑:Mac在睡眠状态下,launchd任务会被跳过。 也就是说,如果你电脑晚上合盖了,那天的日志轮转就不跑了。
作者的选择是:接受这个跳过,不强行唤醒电脑。 因为pmset可以设置定时唤醒,但对电池不好。
学习建议: 如果你也是Mac用户,可以学一下怎么配置plist文件。注意设置LowPriorityIO为true、Nice值为10、ProcessType为Background——这三个一起上,才能确保这个任务在夜深人静的时候不会跟你的其他程序抢资源。
Windows用户?可以用任务计划程序(Task Scheduler)。Linux用户?cron或者systemd timer都行。别跟我说你不会,百度一下三分钟搞定。
第三步:别光裁日志,过期文件也要删
作者还干了一件事:删除30天前的旧产物。比如daily-brief-2.md、project-health-2.md这些文件,每天几个KB到几十KB,一年下来也能堆到几个GB。
bash
⚠️ 这只是演示版!先用 -print 看会删哪些文件,确认无误再把 -print 换成 -delete
find "$LOGDIR" -maxdepth 1 -type f \( \
-name 'daily-brief-2*.md' -o \
-name 'project-health-2*.md' -o \
-name '.-done-' -o \
-name '.vault-ingest-*' -o \
-name '.plist.bak' \
\) -mtime +30 -print
注意这几个事:
1. 文件名必须是精确匹配。原文匹配的是daily-brief-2.md和project-health-2.md,可不是泛化的.md——你要敢用.md,它能把你所有Markdown笔记、项目文档全删了,到时候别说我没提醒你。
2. -maxdepth 1是救命参数。作者自己在文章里说了,她差点因为这个栽跟头——如果不加这个限制,find会递归到~/.claude/的子目录里,把项目数据都删干净。
3. 一定先用-print跑一遍。看看输出列表里有没有你不认识的、不该删的文件。确认无误了,再把-print换成-delete。别等删完了才发现"咦,我今年的项目文件呢?"
这个安全意识,真的不是我在吓你。我也干过这种傻事——写了个清理脚本,没检查通配范围,跑完之后想找的那份重要文档跟着垃圾一起消失了。那个感觉,谁试谁知道。
第四步:别忘记管自己的脚——脚本本身也会生成日志
这可能是最容易被忽略的一点。作者的日志轮转脚本也会生成自己的日志文件log-rotate.log,如果不加处理,这个文件自己也会膨胀。所以她加了一段自截断逻辑:如果自己的日志超过5MB,同样截断到最近2000行。
这叫什么?这叫"管好自己再管别人。" 很多人在写自动化脚本的时候,只想着"我要管好系统日志",结果自己脚本的日志堆到几百MB都不知道。也是醉了。
---
学完这个,你还能用在别的地方吗?
当然能。这个"tail + mv 原子覆盖"的模式,对于任何需要保持文件路径固定、同时控制文件大小的场景都适用。比如:
- 你的聊天机器人日志
- 你的CI/CD流水线日志
- 你的监控脚本日志
- 甚至是你的个人笔记里某个疯狂增长的纯文本文件
---
最后,说点实在的
你可能会问:"kisa,你这么吐槽,那作者做得对吗?"
对,而且干得漂亮。
她的思路非常清晰:问题识别 → 约束分析 → 方案设计 → 实现验证 → 异常处理 → 持续优化。 这不是一个简单的"我写了个脚本就完事了"的博客,而是一个完整的问题解决过程记录。从实际截断记录来看——hook-latency.jsonl从5.1MB砍到174KB,agentmemory.err.log从5.3MB砍到290KB——效果立竿见影。
你觉得我为什么能把她的步骤拆得这么清楚?因为我也干过这种傻事。我曾经也是一个在凌晨三点发现日志文件吃了30GB硬盘的倒霉蛋。当时我的做法是什么?直接删掉。然后第二天发现需要那个日志来排查问题。
所以,学这个不是学技术本身,而是学一种"先想清楚再动手"的态度。
好了,今天的吐槽就到这里。快去检查一下你电脑里有没有正在偷偷长大的日志文件——你以为是岁月静好,其实是它们在背着你慢慢变胖。
别等硬盘报警才后悔。