---
title: "evlog map"
description: "扫描受支持的入口点中的 evlog 日志模式，检查静态可观测性评分，并在不运行处理器的情况下确定修复优先级"
canonical_url: "https://evlog.zhcndoc.com/cli/map"
---
# evlog map

> 扫描受支持的入口点中的 evlog 日志模式，检查静态可观测性评分，并在不运行处理器的情况下确定修复优先级

`evlog map` 会显示哪些受支持的入口点缺少 evlog 日志模式。它会检查你的源代码中是否存在宽事件、上下文、结构化错误以及其他[日志规则](https://evlog.zhcndoc.com/cli/rules)。

选定的框架适配器会发现它能够识别的入口点，例如 API 处理器、获取数据的页面和中间件。报告会为这些检查评分，并列出三个优先检查项。在源代码、CLI 版本和适配器相同的情况下，检查结果也会相同。

扫描不会执行处理器或检查流量。高分并不能证明日志能够到达你的日志接收端，也不能证明日志包含足够的上下文来诊断故障。请阅读[可观测性评分指南](https://evlog.zhcndoc.com/cli/observability-score)，了解受支持的框架以及结果的局限性。

<map-scan-flow>



</map-scan-flow>

```bash [Terminal]
evlog map
```

<warning icon="i-lucide-flask-conical">

**仍处于早期阶段。** 基础已经稳固（基于 AST、经过测试，并具有版本化 JSON 契约），但规则集仍然年轻，目前只有七个框架拥有适配器。一次强化某条规则的发布，可能会改变你未修改的代码的裁决结果，因此如果你根据评分限制拉取请求，请[固定 CLI 版本](https://evlog.zhcndoc.com/cli/ci#pin-the-version)。

</warning>

<prompt :actions="["copy","cursor","claude"]" description="提升我的 evlog map 评分" icon="i-lucide-radar">

在这个项目中运行 `npx evlog map` 并阅读报告。

- 按顺序修复 FIX FIRST 下列出的入口点
- 对每一个入口点，先运行 `npx evlog map <file>` 以查看建议的结构
- 保持改动尽量小：在报告指出缺失的地方添加 `useLogger()`、`log.set()`、`log.audit()` 或 `createError({ why, fix })`
- 重新运行 `npx evlog map` 并确认评分提高了

文档：[https://www.evlog.dev/cli/map](https://www.evlog.dev/cli/map)
规则：[https://www.evlog.dev/cli/rules](https://www.evlog.dev/cli/rules)

</prompt>

## 将它添加到已经投入生产的应用中

`evlog map` 的任何设计都不假设项目是全新的。在受支持的框架中，它读取的是源代码，而不是流量，因此一个三年前发布的应用与脚手架项目的评分方式相同：识别入口点、识别模式、执行相同的静态检查。你会在下一次事故发生之前得到问题列表，而不是在事故发生期间才得到它。不受支持的 Node.js 应用，以及适配器无法识别的包装器，不属于该评分范围。请参见[可观测性评分](https://evlog.zhcndoc.com/cli/observability-score)。

无论代码库存在多久，工作都分为相同的四个步骤：

1. 运行 `npx evlog map`。无需安装、无需部署，也无需让代理监视实时进程。
2. 阅读 **FIX FIRST** 区块。它最多包含三个入口点，并根据它们涉及的内容进行排序：资金、认证和 PII 的优先级高于健康检查。
3. 修复这三个入口点，并分别对它们运行 `npx evlog map <file>`，查看规则预期的结构。列表中的其他内容暂时无需处理。
4. 提交 `evlog.map.json`，并使用 [`--baseline`](https://evlog.zhcndoc.com/cli/ci#the-ratchet---baseline) 以此设置门禁。从该提交开始，已识别的回退都需要经过审查。

大型代码库通常会在第一次运行时得到很低的评分，而这个数字并不是重点。门禁机制是 ratchet，而不是评分：一个从 34 分开始且从未回退的旧应用，比一个起初为 80 分、却在一年内逐渐下降的新应用更健康。

## 确定性的静态检查

`evlog map` 不是运行时基准测试，也不是对应用进行的不稳定测量。它是针对适配器能够识别的入口点，对约定日志规范执行的**确定性静态检查**：这是你可以据此限制拉取请求的检查类型。

确定性意味着，在任何机器上、每次运行中，相同的源代码、CLI 版本和适配器都会产生相同的评分。规则引擎使用 AST 读取源代码，并应用版本化规则集，因此任何结果都不依赖时序、流量或环境。由此会产生三点结论：

- **门禁不会不稳定。** 由于结果不会在不同运行之间变化，`--min-score <n>` 的行为就像真正的测试：门禁通过意味着已识别的要求达到了你设置的最低标准，而不是运行器碰巧成功。确定性评分是你唯一应该用来阻止拉取请求的评分类型。
- **它会逐步提高要求。** `--baseline` 会与已提交的 `evlog.map.json` 进行比较，并对现有入口点中已识别的要求或评分回退失败，其行为与快照测试完全相同。悄悄删除 `log.set` 的重构，无法绕过忽略差异的审查。请参见[ratchet](https://evlog.zhcndoc.com/cli/ci#the-ratchet---baseline)以及[可观测性评分](https://evlog.zhcndoc.com/cli/observability-score)页面中的基线限制。
- **它适合审计。** map 是一种版本化、可复现的构建产物：修订版本相同，`evlog.map.json` 就相同，因此三周前的评分与今天表示的是相同的检查。你可以在审查中引用它，任何人也都可以重新生成它。

它还会在**任何流量出现之前**报告结果。与必须监视实时应用的代理不同，`evlog map` 会在代码写入的瞬间发现缺失的已识别模式，而这正是修复成本最低的时候。将它作为第一天就执行的规范检查，这样你就不会在事故处理中才发现这些缺口。

## 报告

这是一次针对 evlog playground 的真实运行，这是一个拥有 29 个入口点的 Nuxt 应用：

<code-collapse>

```text [evlog map]
▀▀█ █▀▀   分数 /100            evlog-playground · Nuxt
  █ █▀█   ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱    已扫描 29 个入口点
  ▀ ▀▀▀   良好                  ▂▂▂▃▃▃▃▃▃▄▆▆▆▆▆███████████████

覆盖范围
● API 处理器       ▰▰▰▰▰▰▰▰▱▱   79  28 个中有 13 个存在缺口
● 中间件与任务     ▰▰▰▰▰▱▱▱▱▱   45  运行时没有任何日志记录
● 金钱与认证       ▰▰▰▰▰▰▰▱▱▱   71  缺少审计轨迹

优先修复
1. ANY    /api/auth/:all* A — 涉及认证但没有任何日志
   server/api/auth/[...all].ts:1 · evlog.dev/learn/wide-events
2. GET    /api/test/catalog/payment-declined $ — 涉及资金流转但没有审计轨迹
   server/api/test/catalog/payment-declined.get.ts:11 · evlog.dev/use-cases/audit/overview
3. POST   /api/auth/login A — 缺少 log.audit
   server/api/auth/login.post.ts:1 · evlog.dev/use-cases/audit/overview

然后
· 为 /api/test/browser-ingest 添加 useLogger + log.set +4
· 为 /api/payment/process、/api/test/better-auth/whoami 添加 log.audit
· 为 /api/audit/deny 添加 log.set
· 为 /api/audit/with-audit 添加 log.set + createError({ why, fix })
· 为 /api/test/h3-error 添加 useLogger + log.set + createError({ why, fix })
· 为 /api/test/tail-sampling/error 添加 createError({ why, fix })

✓ 已经很稳：/api/audit/catalog/invoice-refund +14
▲ 76 → 86 通过修复上面的 3 项

────────────────────────────
evlog.map.json 已更新 · 这个分数如何计算 → evlog.dev/cli/scoring
▸ evlog map --all 每个入口点 · evlog map <file> 检查单个入口点
  --min-score 80 CI 门槛
```

</code-collapse>

从上到下阅读，每个区块都会回答不同的问题。

### 分数

大号数字是全局评分，满分为 100：它是每个入口点的加权平均值，其中资金和认证路由的权重为双倍，页面的权重为一半。下方的单词是评分等级：`excellent`、`good`、`needs work` 或 `at risk`。

右侧的一排方块代表项目中的每个入口点，从左到右依次为最差到最好。右侧高方块成墙、左侧只有几个矮方块，说明应用整体健康，只存在少数盲点。一整排很低的方块说明应用根本没有任何埋点。在大型项目中，这一排会按终端宽度采样显示，每个桶里显示最差的入口点。

<callout color="neutral" icon="i-lucide-gauge">

完整的计算方式（每条规则的权重、路由权重和等级阈值）请参见[评分](https://evlog.zhcndoc.com/cli/scoring)。

</callout>

### 覆盖范围

分数的来源，会按照你理解应用的方式进行分组，而不是按规则分组。只有当项目中存在相应内容时，这些区域才会出现：一个没有 `pages/` 的 Nuxt 应用不会显示 Pages 行。

<table>
<thead>
  <tr>
    <th>
      区域
    </th>
    
    <th>
      覆盖内容
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      API 处理器
    </td>
    
    <td>
      服务端路由处理器
    </td>
  </tr>
  
  <tr>
    <td>
      页面
    </td>
    
    <td>
      在服务端获取数据的页面
    </td>
  </tr>
  
  <tr>
    <td>
      中间件与任务
    </td>
    
    <td>
      中间件、定时任务、服务端动作
    </td>
  </tr>
  
  <tr>
    <td>
      金钱与认证
    </td>
    
    <td>
      敏感性分类器标记到的每个入口点，无论位于何处
    </td>
  </tr>
</tbody>
</table>

金钱与认证这一行会刻意与其他行重叠。它是缺失事件代价最高的分组，因此它单独成行，并且当其得分低于整个应用时会带有 `⚠` 标记。

### 优先修复

最有收益的三个入口点，先敏感项，再按最差分数排序。每个条目都会给出方法、路径、敏感性标记、说明实际问题的一句话，以及文件、行号和失败规则的文档链接。

`$` 是资金，`A` 是认证，`@` 是 PII。它们来自[敏感性分类器](https://evlog.zhcndoc.com/cli/scoring#mark-what-touches-money-auth-or-pii)，被标记的入口点会被要求额外满足一项要求：审计轨迹。

### 然后

其余存在缺口的内容，按修复方式批量列出，而不是每个入口点单独占一行。`为 /api/test/browser-ingest 添加 useLogger + log.set +4` 表示有 5 个入口点需要同样的两行代码，因此你可以一次性处理它们。

### 进一步提升

只有在项目已经使用了某个 evlog 功能、但某些入口点还没有受益时，才会出现的独立部分：

```text [Excerpt]
进一步提升
你已经在用这些——你的应用还能从中获得更多收益
+ 这些重复错误应该变成目录条目吗？——2 个入口点
   server/api/orders/[id].get.ts:4 · evlog.dev/learn/catalogs
建议不会改变分数。
```

这些是建议，不是缺口。它们以项目中某处已经使用该功能作为前提，绝不会被计为失败，而且 `--min-score` 门槛也不可能因为它们而失败。请参见[机会](https://evlog.zhcndoc.com/cli/rules#opportunities)。

### 最后两行

`✓ Already solid` 会列出无需再修复的入口点，因此一个健康的应用也会得到明确肯定。`▲ 76 → 86 by fixing the 3 above` 表示只修复 **FIX FIRST** 下列出的内容时将得到的评分，这正是应该从那里开始，而不是从其他地方开始的原因。

## 三种视图

默认报告回答“我做得怎么样”。另外两个旗标回答你还会有的另外两个问题。

### 每个入口点

`--all` 会打印检查矩阵：每个入口点一行，按最差情况优先，并按目录分组。

```text [evlog map --all (trimmed)]
evlog-playground · Nuxt · 76/100 · 29 个入口点，最差情况优先

                                            log   ctx   err   audit catch fetch
server/
├─ api/auth/[...all].ts   ▰▰▱▱▱▱▱▱▱▱  20 A  ●     ●     ·     ●     ·     ·
├─ …ment-declined.get.ts  ▰▰▱▱▱▱▱▱▱▱  20 $  ●     ●     ●     ●     ·     ·
├─ …test/h3-error.get.ts  ▰▰▰▱▱▱▱▱▱▱  25    ●     ●     ●     ·     ·     ·
├─ …owser-ingest.post.ts  ▰▰▰▰▰▱▱▱▱▱  45    ●     ●     ·     ·     ·     ·
├─ …t/with-audit.post.ts  ▰▰▰▰▰▰▰▱▱▱  65    ●     ●     ●     ·     ●     ·
├─ …i/auth/login.post.ts  ▰▰▰▰▰▰▰▰▱▱  75 A  ●     ●     ·     ●     ·     ·
├─ …ampling/error.get.ts  ▰▰▰▰▰▰▰▰▱▱  80    ●     ●     ●     ·     ·     ·
└─ …st/wide-event.get.ts  ▰▰▰▰▰▰▰▰▰▰ 100    ●     ●     ·     ·     ·     ·

● 已覆盖   ● 缺口   ·  不适用   $ 金额   A 认证   @ 个人身份信息
每一列检查什么 → evlog.dev/cli/rules
```

每列对应一条规则，顺序按照它们所占的分数排列。圆点表示该规则不适用于此处：一个不会抛出任何内容的处理器，不需要检查其错误是否携带 `why` 和 `fix`，这会显示为圆点，而不是免费通过。空心圆 `○` 表示你已[通过评论禁用的检查](https://evlog.zhcndoc.com/cli/rules#disabling-a-check)。每一列的说明都位于[规则](https://evlog.zhcndoc.com/cli/rules)中。

### 单个入口点

传入路由或文件路径，即可获得单个入口点的完整说明：

```bash [Terminal]
evlog map server/api/auth/login.post.ts
# 或按路由
evlog map /api/auth/login
```

<code-collapse>

```text [evlog map server/api/auth/login.post.ts]
POST   /api/auth/login A   ▰▰▰▰▰▰▰▰▱▱ 75/100
server/api/auth/login.post.ts · Nuxt

扫描此文件的原因
▍ POST /api/auth/login — 服务端处理器

被标记为敏感的原因
▍ auth：路径包含“auth”

检查项
✓ useLogger  每个请求都会发出宽事件
✓ log.set    已通过 log.set() 附加上下文
✗ log.audit  敏感操作但没有审计轨迹  evlog.dev/use-cases/audit/overview

建议结构 — Nuxt
│ export default defineEventHandler(async (event) => {
│   log.audit({
│     action: 'auth.login',
│     actor: { type: 'user', id: user.id },
│   })
│ })

▲ 修复此入口点：75 → 100
```

</code-collapse>

有四点值得注意：

- **为什么扫描此文件**说明 CLI 认为这个文件是什么。如果判断错误，下面的所有内容都会错误，而你可以在这里看到原因。
- **被标记为敏感的原因**显示确切原因，因此发现误报只需要查看一行，而不必面对一个谜团。
- **建议结构**根据实际失败的规则生成，并采用你的框架惯用的写法。审计操作会从路由中读取。`/api/auth/login` 会建议使用 `auth.login`，而不是占位符。
- 当所有要求都通过但仍有建议时，裁决会一分为二：没有需要修复的内容，以及仍有 *n* 项可以提升。

## 什么算作入口点

检测按框架进行，依据文件布局。`--framework` 在检测猜错时会覆盖它。

<framework-tabs>

```text [Nuxt]
server/api/**             → API 处理程序，路径以前缀 /api 开头，方法来自文件名后缀
server/routes/**          → API 处理程序，路径按原样写入
app/pages/**/*.vue        → 页面（Nuxt 4 默认；也包括 pages/ 和 src/pages/）
server/middleware/**      → 中间件
server/tasks/**           → 定时任务
```

```text [Nitro]
routes/**      → API 处理程序，路径按原样写入
api/**         → API 处理程序，路径以前缀 /api 开头
middleware/**  → 中间件
```

```text [Next.js App Router]
app/**/route.ts   → 每个导出的 HTTP 方法对应一个 API 处理程序（GET、POST，…）
app/**/page.tsx   → 页面
middleware.ts     → 中间件
"use server" file → 每个导出的函数对应一个服务器操作
```

```text [TanStack Start]
src/routes/** → 当路由声明了 server handlers 或 createServerFn 时为 API 处理程序，
                否则为页面。会跳过 __root 文件。
```

</framework-tabs>

Next.js 同时支持 `app/` 和 `src/app/`，以及 `src/middleware.ts` 与 `middleware.ts`。没有导出任何 HTTP 方法的 `route.ts` 会被列出一次，方法为 `ANY`。

类型在报告中显示为 `ANY`、`PAGE`、`MID`、`ACT`（服务器操作）、`CRON` 和 `WS`，或者在入口点具有 HTTP 方法时显示为该 HTTP 方法。

<callout color="neutral" icon="i-lucide-shield-off">

没有任何可供插桩内容的入口点会被豁免：evlog 自己的客户端日志摄取端点，它们属于基础设施而不是应用代码，以及什么都不抓取的页面。对它们来说，每条规则都会报告 `n/a`，而不是失败。

</callout>

## 当裁决有误时

你不同意的检查应该只让你多写一条评论，而不该卡住你的 CI 门禁：

```ts [server/api/health.get.ts]
// evlog-map-disable-next-line wide-event, context -- 存活探针，特意静默
export default defineEventHandler(() => ({ ok: true }))
```

这项检查会变为 `n/a`，并附带你的理由，因此它不再扣分；报告还会说明项目禁用了多少项检查，所以高分永远不会掩盖一个完全不记录日志的应用。完整语法请参见[规则](https://evlog.zhcndoc.com/cli/rules#disabling-a-check)。

整个项目都不使用的检查（例如没有错误目录的应用中的 `error-catalog`）可以在 [`evlog.config.ts`](https://evlog.zhcndoc.com/cli/config) 中通过 `map.rules` 一次性关闭。`map.ignore` 按文件排除整个入口点。报告会说明排除了多少个入口点，`--json` 则会在 `ignored` 中携带该数量。

## 标志

<table>
<thead>
  <tr>
    <th>
      标志
    </th>
    
    <th>
      默认值
    </th>
    
    <th>
      作用
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        <entry>
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      按路由路径或文件路径检查单个入口点
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --all
      </code>
    </td>
    
    <td>
      off
    </td>
    
    <td>
      将每个入口点作为检查矩阵显示
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --min-score <n>
      </code>
    </td>
    
    <td>
      off
    </td>
    
    <td>
      当全局评分低于 <code>
        n
      </code>
      
       时以代码 1 退出
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --baseline [ref]
      </code>
    </td>
    
    <td>
      off
    </td>
    
    <td>
      相对于已提交的 map 发生<a href="https://evlog.zhcndoc.com/cli/ci#the-ratchet---baseline">
        回退
      </a>
      
      时以代码 1 退出（路径，或 <code>
        git:<ref>
      </code>
      
      ）
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --baseline-label <text>
      </code>
    </td>
    
    <td>
      ref
    </td>
    
    <td>
      为复制到临时文件的 map 指定报告和注释中的基线名称
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --framework <name>
      </code>
    </td>
    
    <td>
      detected
    </td>
    
    <td>
      强制使用 <code>
        nuxt
      </code>
      
      、<code>
        nitro
      </code>
      
      、<code>
        next
      </code>
      
      、<code>
        tanstack-start
      </code>
      
      、<code>
        hono
      </code>
      
      、<code>
        express
      </code>
      
       或 <code>
        fastify
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --no-write
      </code>
    </td>
    
    <td>
      writes
    </td>
    
    <td>
      跳过写入 <code>
        evlog.map.json
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --verbose
      </code>
    </td>
    
    <td>
      off
    </td>
    
    <td>
      显示逐文件解析警告
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --cwd <dir>
      </code>
    </td>
    
    <td>
      current
    </td>
    
    <td>
      扫描其他目录
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --json
      </code>
    </td>
    
    <td>
      off
    </td>
    
    <td>
      将完整 map 以 JSON 格式输出到 stdout（与 <code>
        --format json
      </code>
      
       相同）
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --format <name>
      </code>
    </td>
    
    <td>
      human
    </td>
    
    <td>
      <code>
        github
      </code>
      
       会将<a href="https://evlog.zhcndoc.com/cli/ci#without-the-action">
        工作流注释
      </a>
      
      写入 stdout
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        --limit <n>
      </code>
    </td>
    
    <td>
      10
    </td>
    
    <td>
      <code>
        --format github
      </code>
      
       输出的最多注释数；GitHub 每个步骤保留十条
    </td>
  </tr>
</tbody>
</table>

可以在 `evlog.config.ts` 中为项目一次性设置 `--min-score` 和 `--baseline`，分别对应 `map.minScore` 和 `map.baseline`。两者同时设置时，命令行标志优先。

## evlog.map.json

每次运行都会将 `evlog.map.json` 写入项目根目录：包括分数、框架、生成该文件的 CLI 版本和规则集版本，以及每个入口点、其检查项、建议、敏感性和自身分数。这与 `--json` 输出的数据相同。

如果不希望生成该文件，可使用 `--no-write`，适用于 CI 运行或快速查看他人的项目。是否提交它取决于你的门禁方式：

- **不对 CI 设置门禁，或仅使用 --min-score**：该文件是构建产物，因此可以将其[加入 gitignore](https://evlog.zhcndoc.com/cli/ci#where-the-map-file-lives)。它与 `--json` 包含相同的数据，因此不会丢失任何内容。
- **使用 --baseline 设置门禁**：像 lockfile 一样跟踪它。ratchet 会与已提交的副本进行比较，因此 `git:<ref>` 只能读取已提交的文件。使用 `evlog map` 重新生成，在差异中审查它，永远不要手动编辑它。

## 它不会告诉你什么

静态分析有其局限性，了解这些局限性，决定了你是信任这个评分，还是被它惹恼。

- **它读取代码，而不是流量。** 一个入口点可以得到 100 分，但如果它附加的上下文有误，运行时仍然会发出无用事件。评分说明的是结构存在。
- **它会跟踪一层导入。** 通过本地模块重新导出的辅助函数可以被解析，`import { useLogger } from '@/lib/evlog'` 也会被计入，但通过你自己的三层抽象传递的 logger 可能无法被识别。
- **七个框架。** Nuxt、Nitro、Next.js App Router、TanStack Start、Hono、Express 和 Fastify 拥有适配器。evlog 集成的其他框架目前还不会被扫描。
- **Hono 路由从字面量注册中读取。** 带有内联函数或命名函数的 `app.get('/path', handler)` 会被计入。计算得到的路径、控制器风格的处理器（`app.get('/users', users.list)`），以及子应用挂载时使用的前缀（`app.route('/api', users)` 会报告不含 `/api` 的子路径）无法被解析。
- **敏感性是一种启发式判断。** 它会读取导入和路由路径。`evlog map <file>` 始终会显示原因，因此错误判断是可见的，而不是悄无声息地发生。

## 下一步

- [规则](https://evlog.zhcndoc.com/cli/rules)：每项检查、满足条件以及确切的修复方式
- [评分](https://evlog.zhcndoc.com/cli/scoring)：权重、等级和敏感性分类器
- [CI](https://evlog.zhcndoc.com/cli/ci)：根据评分限制拉取请求

---

- [规则](https://evlog.zhcndoc.com/cli/rules)
- [评分](https://evlog.zhcndoc.com/cli/scoring)


## Sitemap

See the full [sitemap](https://evlog.zhcndoc.com/sitemap.md) for all pages.
