分数用于与自身进行比较。你可以在修复问题时观察它的变化,也可以据此设置 pull request 的门禁,而不是将其作为与其他项目比较的基准。
一个入口点
每个入口点从 100 分开始,按其未通过的每一项 要求 扣除相应权重,最低降到 0 分。
| 要求 | 权重 |
|---|---|
wide-event | 40 |
audit | 25 |
structured-errors | 20 |
page-error-handling | 20 |
context | 15 |
error-handling | 15 |
通过的规则不会扣分。报告 n/a 的规则也不会扣分,因为它从未适用,所以不会算在入口点头上。机会完全没有权重,也不会出现在这里。
你通过注释禁用的检查也会标记为 n/a,因此不会扣分;报告会统计禁用了多少项,因为部分得分来自已禁用检查时,必须明确说明这一点。
以 playground 里的登录处理器为例:
CHECKS
✓ useLogger 每个请求都发出了 wide event
✓ log.set 使用 log.set() 关联了 context
✗ log.audit 敏感操作但没有审计轨迹
structured-errors 和 error-handling 为 n/a:该处理器既不抛出异常,也不捕获异常。一个要求未通过,因此得分为 100 − 25 = 75。
wide-event 的 40 分高于任何两个较小规则的权重之和。这样,无论从哪个方向看,算术都清晰易懂。下面是 playground 中最差的入口点,它从 20 逐步升到 100,每一行修复都恰好等于其满足的规则权重:
项目分数如何计算
全局分数是每个入口点的平均值,并根据盲区会给你造成多大损失来加权:
| 入口点 | 权重 |
|---|---|
| 标记为资金或认证相关 | ×2 |
| 页面 | ×0.5 |
| 其他所有 | ×1 |
页面的权重更低,因为吞掉 fetch 错误的页面会带来比可观测性缺口更差的用户体验,而且它们通常也是应用中数量最多的文件。敏感处理器的权重加倍,因为那正是你需要事件的地方。
三个入口点:一个得分为 75 的敏感处理器、一个得分为 100 的普通处理器,以及一个得分为 50 的页面:
(75 × 2) + (100 × 1) + (50 × 0.5) 275
───────────────────────────────── = ───── = 79
2 + 1 + 0.5 3.5
没有可评分入口点的项目目前得分为 100。这是一个空结果,并不代表埋点已完整完成。在解读分数之前,请检查检测到的框架和入口点数量。
如何分配等级
| 分数 | 等级 |
|---|---|
| 90–100 | 优秀 |
| 70–89 | 良好 |
| 50–69 | 需要改进 |
| 0–49 | 有风险 |
如何对文件进行分类
除了分数之外,每个入口点还会被分类,这决定了 JSON 中 summary 块的统计方式,也决定了报告中的覆盖率行如何构建。
| 类别 | 何时 |
|---|---|
instrumented | 同时传递了 wide-event 和 context 的处理程序,或者能够处理其 fetch 错误的页面 |
partial | 只传递了两者之一的处理程序 |
dark | 两者都未传递的处理程序,或者吞掉 fetch 错误的页面 |
exempt | 没有需要埋点的内容——evlog 自身的基础设施,或者没有发起任何 fetch 的页面。它与你自己的入口点分开统计,而不是作为一个缺口来统计 |
dark 表示分析器未识别出所需的 evlog 埋点或页面错误处理。其他日志记录器或不受支持的抽象仍可能产生有用的证据。在将其分类视为没有日志之前,请检查代码。
标记涉及资金、认证或 PII 的内容
敏感度决定了一个入口点是否提升为双倍权重,并添加 audit 要求,所以准确了解它是如何判定的很重要。
资金:$
- 导入
stripe、@stripe/stripe-js、paddle-sdk或@lemonsqueezy/lemonsqueezy.js - 路径 包含
checkout、payment、billing、invoice、refund、subscription、charge或payout
认证:A
- 导入
better-auth、next-auth、lucia、@auth/core或@auth/nextjs - 路径 包含
auth、oauth、login、logout、signin、signup、register、password、token、session、mfa或otp
PII:@
字段匹配 email、phone、address、ssn 或 iban,并且在同一个处理程序中存在写入调用(create、update、insert、upsert)。
金融和认证属于 high 敏感度:双倍权重,并且需要审计轨迹。PII 属于 medium:没有额外要求,但会在报告中标记。
匹配是如何工作的
有两个决定避免了噪音。
导入是从 AST 中读取的。 只有当某个包确实被导入时才计数,所以 // TODO: drop stripe 注释不会让某条路由处理金融相关内容。
路径术语匹配完整单词,同时允许复数形式。/api/authors 不是认证路由,而 /api/refunds 是资金路由。这一点比看起来更重要:被错误标记的路由会被分配一个没有理由满足的 25 分要求,并在平均分中按双倍计算,这是让整个分数失去可信度的最快方式。
当你检查某个入口点时,每个原因都会完整显示,所以错误调用只需一行就能发现:
FLAGGED SENSITIVE BECAUSE
▍ auth: path says "auth"
诚实地解读分数
- 高分并不等于良好的可观测性。 它只说明结构已经具备:每个入口点都有事件,附带上下文,错误可以解释,敏感操作有审计。你附加的上下文是否正是你将来需要的上下文,这是静态分析器无法判断的。最佳实践 →
- 比较的是运行结果,而不是项目。 一个有 200 条路由、得分 70 的应用,状态比一个只有 6 条路由、得分同样为 70 的应用更好。
- 重点关注
dark和 `资金与认证,而不是总分。这两个地方正是下一次事故最可能潜伏的地方。