先说结论:生产环境里的日志,不是越详细越好。
一个高吞吐系统,如果把每个请求、每次重试、每个数据包都原样打出来,出问题的时候,你可能确实能搜到更多记录——前提是磁盘没被写满,日志采集没积压,你也有足够时间从里面找出真正有用的那几条。
我做数据采集这几年,对日志的要求越来越简单:先保证系统还能看见异常,再考虑把过程记录得多细。
这听起来有点反直觉。排查问题不就该多留证据吗?
是。只不过,证据多和有用,是两回事。
一次故障,可能产生两次日志风暴
拿数据采集任务举个例子。
一个工作节点持续向外发送请求,每次请求都会经过调度、连接、响应处理、解析、入库等步骤。如果每个步骤都打一条成功日志,正常运行时,日志量已经和请求量一起增长。
到了故障时,事情会更麻烦。
某个目标站点响应变慢,请求开始超时,系统触发重试。同一个请求从一条超时,变成多次重试、多个异常堆栈、若干条连接失败记录。假设原来每个请求记录一条,现在一次失败连同重试产生十几条,日志量就会在业务最脆弱的时候突然放大。

这时候,磁盘写入、日志采集、压缩、网络传输、索引,都要消耗资源。如果业务和日志共用磁盘或网络,日志风暴甚至可能挤占业务本来就不够用的资源。
还有一种情况更隐蔽:磁盘没满,采集端却开始积压。工程师在日志平台上搜不到刚刚发生的错误,以为应用没报错,实际上只是日志还没送到。
日志系统本身,也需要被监控。
至少要知道日志队列积压了多少、是否有丢弃、采集延迟多久、磁盘还剩多少空间。否则你看到的「没有错误日志」,未必等于「没有错误」。
每条请求都打日志,为什么还是找不到原因?
因为日志数量解决的是「有没有记录」,不是「能不能判断」。
比如同一时间刷出几万条这样的记录:
请求失败,准备重试。
这条日志有用吗?有一点。它说明请求失败过。
但如果没有目标服务、失败阶段、错误类型、耗时、重试次数,也没有关联标识,你很难继续往下查:是连接没建起来,还是对方返回了错误?是某一个目标出了问题,还是所有任务都在超时?这条重试又属于哪个原始任务?
反过来,一条字段完整的结构化日志,可能比几百条「开始请求」「请求完成」更有用。
我通常会先想三个问题:
- 这条记录能不能帮助判断发生了什么?
- 出问题时,能不能用它找到受影响的任务或请求?
- 如果把它删掉,是否会失去其他信号无法补回的关键上下文?
三个问题都答不上来,那这条日志就值得重新考虑。
当然,日志不是按「一条顶几百条」这么简单算的。详细记录有时确实必要,比如定位协议层问题、复现特定解析错误。区别在于:详细记录应该有明确范围和期限,而不是默认对所有流量永久开启。
哪些信息进日志,哪些进指标?
这地方很多人踩坑——把日志当成了万能存储。
我习惯按信息要回答的问题来分。

指标:先看系统哪里不对
指标适合回答「整体情况怎么样」。
比如请求总量、成功率、超时数量、响应耗时分布、队列长度、重试次数、磁盘使用率。这些数据天然适合按时间窗口聚合,用来看趋势和触发告警。
假设某个采集任务的成功率下降,指标可以先告诉我:问题从什么时候开始,影响了哪个目标或哪个任务类型。
但指标通常不能直接回答「某一次请求为什么失败」。那就需要继续看日志或追踪记录。
指标标签也要克制。目标服务、任务类型、错误类别这类取值范围相对可控的字段,通常可以作为标签;请求 ID、完整 URL、用户 ID 这类可能产生大量不同取值的字段,不适合随手塞进指标标签,否则时间序列数量可能迅速膨胀,监控系统自己的成本也会上来。
日志:留下可定位的事件
日志更适合回答「具体发生了什么」。
一次任务失败,至少应该能看到任务标识、发生时间、所在服务、处理阶段、错误类别、耗时和重试次数。如果上下文允许,再补上目标服务、状态码、版本号等字段。
比如一条超时日志,既要说清楚是连接超时还是读取超时,也要让人能从任务 ID 找到相关记录。
成功日志怎么办?
不一定全留。对大量重复、低风险的成功请求,可以用聚合指标观察整体情况,再按比例采样保留部分详细日志。至于关键状态变化——任务开始、任务结束、配置变更、重要处理结果——是否逐条记录,要看排查和业务需要。
追踪:把一次请求经过的服务串起来
当一个任务穿过调度服务、采集节点、解析服务和入库服务,仅靠各自的时间戳拼过程,排查起来很费劲。
这时需要关联标识。
简单说,就是给一次请求或任务一个可传递的标识,让不同组件记录同一个标识。你看到解析失败后,可以拿这个标识去找前面的请求结果和后面的重试记录。
如果系统已经接入分布式追踪,可以进一步记录各阶段的跨度和耗时,看看时间究竟卡在连接、解析还是入库。关联 ID 解决的是「找到同一件事」,追踪还会补上「经过了哪些阶段、各阶段花了多久」。
这里有个前提:标识得跨服务、消息队列和异步任务正确传递。中间丢了一次,上下文就会断开。重试场景也要区分原始任务与具体尝试:同一个任务可以保留共同的任务 ID,每次尝试再有自己的尝试 ID,免得把多次失败误看成多笔独立业务。
审计记录:回答谁做了什么
审计记录和普通故障日志,不是同一个用途。
比如谁修改了采集任务配置、谁导出了数据、谁调整了访问权限,这些操作可能需要保留操作主体、对象、时间、动作和结果,方便事后追溯。
它们不应该因为普通日志量太大,就跟着被随意采样或丢弃。保存多久、谁能查看、是否需要防篡改,要按业务要求和适用的合规要求单独设计。
同样需要克制的是记录内容:为了排查方便,把密码、令牌、完整响应正文或个人信息直接写进去,后面往往会变成另一个问题。能不记录就不记录,确实需要时做脱敏、权限控制和保存期限管理。
采样不是「随便扔掉一部分」
很多团队一想到降日志量,第一反应就是:所有日志统一采样。
我不建议这么做。
正常请求和异常请求,价值不一样;同一种错误的第一次出现,和一秒钟内重复出现的第十万次,价值也不一样。
一种更容易落地的做法是:
- 常规成功事件按比例采样。采样率根据流量、成本和排查需要调整,保留必要上下文。
- 重要异常尽量保留,但要防重复风暴。可以保留首次出现、错误恢复、状态变化和周期性摘要;重复错误在摘要里记录数量、时间范围和代表样本。
- 关键审计事件走独立策略。不能因为日志管道拥堵,就默认允许丢弃。
- 针对特定任务临时提高详细度。设置作用范围、失效时间和数据保护措施,排查结束后自动恢复。
这不意味着「异常永远不能采样」。当某类错误已经把系统压得喘不过气时,对重复异常做限流和聚合是有必要的。关键是别只留下一条孤零零的「发生过错误」,却把次数、持续时间和受影响范围一起丢了。
还有个细节:按单条日志随机采样,可能把同一请求的前后步骤拆散。如果要靠关联 ID 还原一次请求的过程,更适合按请求或追踪整体决定是否保留;需要在请求结束后根据结果判断是否保留时,也可以评估尾部采样,但得考虑它带来的缓存和处理成本。
采样之后,日志条数也不能直接当真实请求数。采样率要可见,整体请求量和错误量最好由独立指标统计;如果要依据采样记录估算,还得考虑采样概率和偏差。
聚合能省空间,但别把现场一起压没了
采集系统里经常会遇到重复错误。比如同一个目标连续出现大量连接超时,每条报错内容几乎相同。
这时可以按目标服务、错误类别、处理阶段等维度聚合,定期输出一条摘要:这一时间段发生了多少次,最早和最晚出现的时间是什么,保留哪些代表性任务 ID。
但聚合不能只看错误文案。
同样是「请求超时」,连接超时和读取超时不是一回事;同样是「解析失败」,解析器版本不同,原因也可能不同。聚合维度过粗,就会把不同问题压成同一种,省下了空间,却损失了排查能力。
我会先看这条错误要帮助谁做什么判断,再定聚合维度。字段不够,摘要就只是把噪声换了个包装。
如果从头设计,我会先做这几件事
不用一上来就追求一套很重的可观测平台。对多数系统,先把下面几件事做好,排查体验就会有明显区别。
第一步,画出一次任务的主要过程。从接收任务到请求、解析、入库、重试,标出会跨越哪些服务或队列,以及每个阶段可能失败在哪里。
第二步,统一基本字段。至少让不同组件对时间、服务名、环境、任务 ID、请求或追踪 ID、错误类别、耗时使用一致的字段约定。时间要有明确时区;跨机器排查也要关注时钟同步,否则事件顺序可能对不上。
第三步,先把关键指标立起来。请求量、成功率、错误类别、延迟分布、重试量、队列积压,以及日志管道自身的延迟和丢弃情况,先选与业务有关的维度。告警也要区分业务故障和日志采集故障,避免日志平台没消息时所有人都以为系统正常。
第四步,明确日志的保留策略。哪些成功事件采样,哪些异常需要保留样本和计数,哪些记录属于审计,分别设定保存期限、访问权限和容量预算。磁盘接近上限时怎么处理,也要提前决定,不能等写满了再临时删文件。
第五步,留一个可控的临时排查开关。按任务、目标或实例开启详细日志,限制时长和数据范围,同时确保开关本身不会把高流量节点拖垮。默认关闭、到期自动恢复,比靠人记得关稳妥。
最后再做一次演练:挑一个已知问题,看看能不能从告警找到受影响范围,再用关联 ID 找到具体任务,最后判断失败发生在哪个阶段。

如果这条路走不通,日志写得再多,也只是把问题埋得更深。
我现在看一套日志设计,最先问的不是「一天存了多少」,而是出故障后,值班的人能不能在几分钟内判断:哪里坏了、影响了谁、下一步该查什么。
至于到底保留多少细节,得看你们的流量、风险和排查成本,没有一个适合所有系统的统一数字。