3 步 · 3 段可复制提示词 · 约 10 分钟读完
站内精选
核心结论

订单同步接口每天 4,000 次调用,0.3% 返回 500,一天约 12 次。日志只有一行 Internal Server Error,排查靠猜,上次花了 3.5 小时。这次加 3 层日志:入口记参数、处理层记分支和关键变量、出口记耗时与异常栈,用一个 trace id 串起来。每请求约 6 行,每天 2.4 万行。同类问题再出现,20 分钟定位。

订单同步接口每天 4,000 次调用,其中 0.3% 返回 500,一天约 12 次。日志里只有一行 Internal Server Error,没有参数、没有分支、没有耗时。上次排查花了 3.5 小时,靠三次改代码加日志试出来的。这次加 3 层日志,同类问题再出现,20 分钟定位。

一句话结论

500 不是错误信息,是让你开始猜的信号。它只说「服务器出错了」,不说哪个参数、哪个分支、哪一行。所以真正要加的不是「更多日志」,是三层有结构的日志:入口记参数、处理层记分支和关键变量、出口记耗时与异常栈,三层用同一个 trace id 串起来。这次每请求约 6 行、每天 2.4 万行,日志量不大,但定位时间从 3.5 小时降到 20 分钟。

这篇解决什么问题

三个症状。一是报错信息没有信息量:一行 500,连是哪个参数引起的都不知道,只能拿 12 条报错样本比来比去。二是日志是散的:入口一条、异常一条、数据库一条,没有共同标识,拼不出一个完整请求。三是只能复现,不能回溯:加了日志跑一遍不复现,说明问题是条件下的,条件没抓住,改三次也可能碰不上。

根子是把日志当成出事之后的证据,它其实是出事之前的记录。等出事了再想加日志,问题已经过去了,只能等下一条报错。正确做法是在正常的时候就把结构埋好——三层日志平时不显眼,出事时能一条线拉出整个请求。

开始前要准备什么

  • 接口的完整调用链:从收到请求到返回,中间经过哪些层、几次数据库查询、几次外部调用。画出来才知道该在哪埋点。
  • 一批报错的样本,12 条最好,最少 3 条。用来找共性,也用来验证日志埋得准不准。
  • 日志规范:格式统一(时间、trace id、层级、内容)、敏感字段处理规则、留存期。
  • 一条纪律:不记敏感值。手机号、地址、证件号这类不记原文,记长度或哈希。日志泄露和接口泄露一样严重。

具体怎么做

第一步:先画调用链,标出可能出错的位置

不画链就埋点,一定漏。这次链路是:收请求 → 参数校验 → 查订单 → 查库存 → 组装 → 调外部履约 → 写回 → 返回,8 个环节。把 12 条历史报错按「最可能出错的环节」贴上去,发现 9 条集中在「查库存」和「组装」两处。

这一步 40 分钟,产出一张图:8 个环节、每个环节标「必须记什么」。入口和出口必记,中间 6 个环节里只给 2 个高风险环节加详细埋点——全都加,日志会淹掉有用信息。

这是一个订单同步接口的调用链(8 个环节:收请求 → 参数校验 → 查订单 → 查库存 → 组装 → 调外部履约 → 写回 → 返回),以及 12 条历史 500 报错的样本(只有时间,无其他信息)。

请帮我设计日志埋点方案,只设计不写代码:
1 按 8 个环节,标出哪些环节「必须记日志」、哪些「可以只记耗时」,说明判断依据(出问题的频率、该环节的复杂度);
2 入口层:列出该记哪几类字段(标识类、判断类、异常类),并说明为什么不该把全部参数都打出来;
3 处理层:给出「分支日志」的写法——每行记什么、什么时候记,要求能在事后还原「走的是哪条路」;
4 出口层:列出必记项,包括耗时怎么分段(总耗时、外部调用耗时、数据库耗时)。

要求:只设计方案不写代码;每个环节要说明「记这个是为了回答什么问题」;不许建议记录敏感字段原值,给出替代方案。

第二步:三层埋点,用 trace id 串起来

入口层:生成 trace id,记三类字段——标识类(订单号、用户 id、来源渠道)、判断类(走哪个分支的关键值,比如库存状态、会员等级)、异常类(不在预期范围内的值,比如数量为负、金额为空)。不记全量参数,40 多个字段里只记 8 个。

处理层:每个高风险环节进入时记一行「进入 X 环节,关键变量 = 值」,出来时记一行「离开 X 环节,结果 = 值、耗时 = N ms」。6 个环节 × 2 行 = 12 行,但只给 2 个高风险环节加,实际 4 到 6 行。

出口层:记返回码、总耗时、分段耗时(外部调用、数据库)、异常栈(有则记)。异常栈要带 trace id,这样从日志能直接跳到这次请求的全部记录。

这是我的接口代码结构(8 个环节的伪代码,见下方)和第一步定好的埋点位置。

请给出日志埋点的具体写法,只写日志行,不改业务逻辑:
1 trace id:给出生成规则(组成、长度),说明为什么不需要全局唯一;
2 入口层:给出 3 到 5 行日志的具体内容模板,每行标注「这行是为了回答什么问题」;
3 处理层:给出「进入/离开」两行日志的模板,说明关键变量该记哪几个、为什么不记全部;
4 出口层:给出耗时分段的记法(总耗时、外部调用、数据库各一行还是一行内分字段)。

硬约束:不许在日志里出现手机号、地址、证件号的原值,给出替代写法(长度、哈希、脱敏前 3 后 4);日志格式统一为「时间 | trace | 层级 | 环节 | 内容」;不要建议引入日志框架或第三方服务。
输出格式:按层级分段,每行日志给出模板字符串。

第三步:拿历史报错验证埋点够不够

埋完不能就算完,要验证。方法是拿那 12 条历史报错「假装重放」——如果当时有这套日志,能不能定位?这次逐条走了一遍,有 2 条走不通:一条是外部履约服务超时,出口层记了耗时但没记「调的是哪个外部地址、返回了什么」;补上之后 12 条全部能定位。

验证这一步 30 分钟,但它决定了日志是「有用」还是「看起来有用」。没有这一步,你可能埋了 20 行日志,真出事时还是差那一行。

这是我按三层方案补完的日志(见下方 12 条日志样例)和 12 条历史报错的场景描述。

请做两项验证:
1 逐条判断:如果当时有这套日志,能不能定位到这 12 条报错的原因?能的说明靠哪几行,不能的指出缺哪条信息;
2 对不能定位的,给出补充的日志行(只补缺的那一条,不要重写整套)。

另外评估:这套日志每天约 2.4 万行(每请求 6 行 × 4,000 次),判断这个量级合不合适,以及留存期该设多久(正常日志 / 错误日志分开给)。
要求:只验证和补充;第 2 项补的日志要指明插在哪个环节;留存期要给出计算依据(每行多少字节、多少天)。

实测记录

素材是订单同步接口(8 个环节)、每天 4,000 次调用、0.3% 报 500(约 12 次/天)、12 条历史报错样本。设计埋点 40 分钟、加代码 60 分钟、验证 30 分钟,合计 130 分钟。

结果:三层日志落地,每请求约 6 行(入口 3 行、处理层 2 到 3 行、出口 1 到 2 行),每天约 2.4 万行、约 5MB。拿 12 条历史报错做「假装重放」验证,10 条能定位、2 条不能——缺的是外部调用地址和返回内容,补上后 12 条全部能定位。

两个数值得记。一是12 条历史报错里 9 条集中在 2 个环节(查库存、组装),所以埋点只给这 2 个环节加详细日志,其余只记耗时——全加会让日志淹掉有用信息。二是定位时间从 3.5 小时到 20 分钟,差 10 倍。3.5 小时里有大半是「改代码加日志 → 等复现 → 看输出」的循环,日志够了这个循环就没了。

最容易错的 3 个地方

第一,把全部参数打出来。40 多个字段全记,日志被淹,还要处理敏感信息。入口只记 8 个:标识、判断、异常三类。手机号地址这类记长度或哈希,别记原文。

第二,只记异常栈。栈只告诉你最后在哪崩,不告诉你为什么走到那。这次问题是有字段在某个条件下为空,走到第 3 个分支才崩——加分支日志后,「进入分支 3、字段 x 为空」直接暴露了前面漏的判断。

第三,不验证就上线。埋完 20 行日志,以为够了。拿 12 条历史报错逐条走一遍,这次有 2 条走不通,缺外部调用地址和返回内容。不验证,这 2 类问题下次还是查不出来。

可复用的东西

三层埋点:入口记参数(标识 / 判断 / 异常三类)、处理层记分支进出、出口记耗时与栈。三层用同一个 trace id 串。

只给高风险环节加详细日志:按历史报错分布决定,集中在哪就加哪。这次 12 条里 9 条在 2 个环节。

入口只记 8 个字段:不全记。敏感值记长度或哈希,永远不记原文。

历史报错当测试集:埋完拿历史样本逐条走,看能不能定位。走不通的补那一行。

耗时分段:总耗时、外部调用、数据库分行记。不然「慢」和「错」混在一起分不清。

常见问题解答

为什么不在入口把所有参数全打出来

会淹掉有用的信息,还有安全问题。这次一个请求的完整参数有 40 多个字段,其中包含手机号和地址,全打出来既占空间又违规。做法是入口只记三类:标识类(订单号、用户 id)、判断类(走哪个分支的关键值)、异常类(不在预期范围内的值)。其余字段记长度或哈希。

处理层记分支有什么用,不是有异常栈吗

异常栈只能告诉你最后在哪一行崩了,不能告诉你为什么走到那一行。这次的问题是有个字段在某个条件下为空,走到第 3 个分支才崩,栈里只有「Cannot read property of null」。加上分支日志后,能看到「进入分支 3、字段 x 为空」,直接就知道前面哪个判断漏了。

trace id 怎么生成和传递

在入口生成一个,放进请求上下文,后面每层日志都带上。字符串由时间戳、随机数和机器标识拼成,不需要全局唯一,只要在同一天内不重复就够。传递方式看技术栈:同进程用上下文变量,跨服务放在 header 里。这次是单服务,用一个请求级的变量就够。

每天 2.4 万行日志会不会把磁盘写满

不会,但要设留存期。一行约 200 字节,2.4 万行约 5MB/天,30 天 150MB。设置 30 天自动清理,正常日志和错误日志分开存——错误日志留 90 天,正常日志留 7 天。这次算下来存储成本可以忽略,真正的成本是「日志太多导致查起来慢」,所以入口和出口记全,处理层只记分支不记中间值。

小程序阅读免费
微信扫码进入小程序,按岗位找 AI 实操步骤
微信扫码进小程序
按岗位找 AI 实操步骤 · 提示词可收藏

发表回复

后才能评论