---
title: "evlog.config"
description: "一个 evlog.config.ts 统一设置 evlog map 检查的内容、evlog logs 读取的位置，以及应用使用的采样、脱敏和 drain。"
canonical_url: "https://evlog.zhcndoc.com/cli/config"
---
# evlog.config

> 一个 evlog.config.ts 统一设置 evlog map 检查的内容、evlog logs 读取的位置，以及应用使用的采样、脱敏和 drain。

没有配置文件时，CI 门控必须在每次 `evlog map` 运行时通过标志设置；你决定忽略的检查要逐文件禁用；采样和脱敏则散落在调用 `initLogger` 的文件中。`evlog.config.ts` 统一保存这些内容，预设可以将它们从一个仓库带到另一个仓库。CLI 会读取文件但不会执行它。应用会执行它：Nuxt 和 Nitro 模块会自行加载，其他应用则导入它。

下面的应用基于共享预设，重新启用一项检查，并将开发路由排除在 map 之外：

<code-group>

```ts [evlog.config.ts]
import { defineEvlog } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import preset from './evlog.preset'

export default defineEvlog({
  extends: preset,
  service: 'checkout',
  drain: createAxiomDrain(),
  sampling: { rates: { info: 25 } },
  map: {
    rules: { 'audit-coverage': 'on' },
    ignore: ['src/routes/_dev/**'],
  },
  logs: { limit: 100 },
})
```

```ts [evlog.preset.ts]
import { defineEvlog } from 'evlog'

export default defineEvlog({
  sampling: { rates: { info: 10, debug: 0 } },
  redact: { paths: ['user.password', 'card.number'] },
  map: { rules: { 'error-catalog': 'off', 'audit-coverage': 'off' }, minScore: 70 },
})
```

</code-group>

`evlog config` 会按设置的作用分组打印合并结果，并显示设置所在的行；文件没有说明的地方会补充 evlog 实际使用的值：

```bash [Terminal]
evlog config
```

```text [Output]
evlog.config.ts · extends ./evlog.preset → evlog.preset.ts

Service
  service      checkout       evlog.config.ts:7
  environment  from NODE_ENV  default

Sampling
  trace  0%      default
  debug  0%      evlog.preset.ts:4
  info   25%     evlog.config.ts:9
  warn   100%    default
  error  100%    default
  fatal  always  default

Redaction
  redact    on                                                          evlog.preset.ts:5
  builtins  creditCard, email, ipv4, phone, jwt, bearer, iban, secrets  default
  paths     user.password                                               evlog.preset.ts:5
            card.number                                                 evlog.preset.ts:5

Pipeline
  drain  createAxiomDrain()  evlog.config.ts:8

CLI · read by evlog map and evlog logs
  map.rules.error-catalog   'off'                   evlog.preset.ts:6
  map.rules.audit-coverage  'on'                    evlog.config.ts:11
  map.minScore              70                      evlog.preset.ts:6
  map.ignore                ['src/routes/_dev/**']  evlog.config.ts:12
  logs.limit                100                     evlog.config.ts:14
```

每个脱敏路径都会保留添加它的文件行号，因此预设提供的路径不会看起来像应用自己的设置。使用 `routes` 时，Service 部分会变成 Services，并按 evlog 匹配路由的顺序列出每个路由的服务名称，首个匹配项优先。不会产生实际效果的速率会在对应行下方给出警告，例如 `fatal` 速率，因为 fatal 事件始终保留。

文件计算出的值（例如 `createAxiomDrain()`）会显示生成它的代码。`--json` 会将文件中写入的设置作为 `cli` 和 `app` 列表返回，每项包含 `{ path, value, source }`；`redact.paths`、`redact.patterns` 和 `sampling.keep` 的每一项各占一条，计算出的值写为 `{ "runtime": "createAxiomDrain()" }`，正则表达式写为 `{ "regexp": "/acct_\\w+/g" }`。当 `nuxt.config.ts` 或 `nitro.config.ts` 向 evlog 模块传入选项时，`moduleOptions` 为 `{ file, readable }`；如果选项在运行时计算，`readable` 为 false，否则为 `null`。被这些选项替换的设置会携带 `overrides: { value, source }`，其中包含配置文件的值。

## evlog 在哪里查找文件

CLI 以及 Nuxt 和 Nitro 模块会按此顺序查找 `evlog.config.ts`、`evlog.config.mts`、`evlog.config.js` 和 `evlog.config.mjs`，从应用的软件包目录开始向上查找到工作区根目录。找到的第一个文件会独立生效。配置不会级联，因此拥有自己 `evlog.config.ts` 的应用会忽略根目录文件，除非它继承该文件。

`map.ignore`、`map.baseline` 和 `logs.dir` 中的路径相对于正在映射或读取的软件包，而不是配置文件。因此，单仓库根目录的一份配置就可以适用于其中的所有应用。

## 从配置中门控 map

`evlog map` 会读取 `map` 部分，命令行传入的标志优先于相同的配置项。

<table>
<thead>
  <tr>
    <th>
      设置
    </th>
    
    <th>
      接受值
    </th>
    
    <th>
      标志
    </th>
    
    <th>
      作用
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        map.rules
      </code>
    </td>
    
    <td>
      <code>
        { [id]: 'on' | 'off' }
      </code>
    </td>
    
    <td>
      无
    </td>
    
    <td>
      为所有入口点关闭某项检查，或重新启用被预设关闭的检查
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        map.ignore
      </code>
    </td>
    
    <td>
      glob 列表
    </td>
    
    <td>
      无
    </td>
    
    <td>
      将文件匹配 glob 的入口点排除在 map 之外
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        map.minScore
      </code>
    </td>
    
    <td>
      0 到 100 的整数
    </td>
    
    <td>
      <code>
        --min-score
      </code>
    </td>
    
    <td>
      全局分数低于该值时以 1 退出
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        map.baseline
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
      
      、路径或 <code>
        git:<ref>
      </code>
    </td>
    
    <td>
      <code>
        --baseline
      </code>
    </td>
    
    <td>
      相比已提交的 map 出现回归时以 1 退出，<code>
        true
      </code>
      
       表示 <code>
        evlog.map.json
      </code>
    </td>
  </tr>
</tbody>
</table>

`map.ignore` 匹配入口点声明所在的文件。Hono 应用在一个文件中声明多个路由时，一个 glob 会将它们全部排除，不能只排除其中一个。

这些 id 来自[规则](https://evlog.zhcndoc.com/cli/rules)。除 `wide-event` 和 `context` 外，所有检查都可以关闭，因为 map 会根据它们将入口点分为已接入、部分接入和黑暗入口。要排除这两类入口点，请改用 `map.ignore`。

在配置中关闭的检查会在每个入口点显示为 `n/a`，并在 `--json` 中以 `turned off in evlog.config` 作为消息。报告会在分数上方说明配置改动，并指出门控来自哪个设置：

```text [Output]
evlog.config.ts: error-catalog off, 1 entry point ignored
█▀█ ▀▀█   score /100              checkout · Hono
█▀█  ▀█   ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱    2 entry points scanned
▀▀▀ ▀▀▀   good                    ▆█

 GATE  score 83 meets map.minScore 70 — exit code 0
```

在同一项目中运行 `evlog map --min-score 95` 会以 95 作为门槛，并显示 `--min-score 95`。如果只想为一个处理器关闭检查，而不是关闭整个项目，请继续在代码旁使用[禁用注释](https://evlog.zhcndoc.com/cli/rules#disabling-a-check)。

## 从其他目录读取日志

`evlog logs` 会读取 `logs` 部分，其命令行标志同样优先。

<table>
<thead>
  <tr>
    <th>
      设置
    </th>
    
    <th>
      接受值
    </th>
    
    <th>
      标志
    </th>
    
    <th>
      作用
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        logs.dir
      </code>
    </td>
    
    <td>
      路径
    </td>
    
    <td>
      <code>
        --dir
      </code>
    </td>
    
    <td>
      读取此目录而不是 <code>
        .evlog/logs
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        logs.limit
      </code>
    </td>
    
    <td>
      大于或等于 1 的整数
    </td>
    
    <td>
      <code>
        --limit
      </code>
    </td>
    
    <td>
      最多显示这么多事件
    </td>
  </tr>
</tbody>
</table>

`evlog map` 的 `--format`、`--verbose` 和 `--limit` 仍然只能作为标志使用。它们描述一次运行，而不是项目。

## 写入 CLI 可以读取的值

CLI 会解析 `evlog.config.ts` 但从不执行它，因此 `map` 和 `logs` 下的每个值都必须是字面量、`const`，或从本地文件导入的值。调用、环境变量或从软件包导入的值都会使命令停止：

```text [Output]
logs.limit in evlog.config.ts:14 is computed at runtime
→ Write the value inline, as a const, or import it from a local file
```

文件的其余部分供应用使用，可以计算任意内容：drain、`enrich` 函数，或从 `process.env` 读取的采样速率。CLI 会列出这些值，但不会执行它们。

## 使用 `extends` 共享设置

`extends` 接受另一个配置，该配置可以从本地文件或软件包导入。发布到 npm 的预设就是一个默认导出 `defineEvlog({ ... })` 的普通模块，因此团队安装后即可继承它：

```ts [evlog.config.ts]
import { defineEvlog } from 'evlog'
import preset from '@acme/evlog-preset'

export default defineEvlog({
  extends: preset,
  service: 'checkout',
})
```

CLI 会沿着软件包的 `exports` 找到其发布的文件并以相同方式读取，因此预设中的 `map` 和 `logs` 也必须是字面量。

设置按类型合并：

<table>
<thead>
  <tr>
    <th>
      配置中的内容
    </th>
    
    <th>
      结果
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      标量或函数：<code>
        service
      </code>
      
      、<code>
        drain
      </code>
      
      、<code>
        enrich
      </code>
      
      、<code>
        keep
      </code>
    </td>
    
    <td>
      配置文件的值替换预设的值
    </td>
  </tr>
  
  <tr>
    <td>
      对象：<code>
        sampling.rates
      </code>
      
      、<code>
        routes
      </code>
      
      、<code>
        env
      </code>
      
      、<code>
        map.rules
      </code>
    </td>
    
    <td>
      按键合并，每个键以配置文件为准
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        redact.paths
      </code>
      
      、<code>
        redact.patterns
      </code>
      
      、<code>
        sampling.keep
      </code>
    </td>
    
    <td>
      先使用预设条目，再使用配置文件条目
    </td>
  </tr>
  
  <tr>
    <td>
      其他列表：<code>
        map.ignore
      </code>
      
      、<code>
        include
      </code>
      
      、<code>
        exclude
      </code>
    </td>
    
    <td>
      配置文件的列表替换预设的列表
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        plugins
      </code>
    </td>
    
    <td>
      按 <code>
        name
      </code>
      
       合并，配置文件中的同名插件替换预设插件
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        redact: false
      </code>
    </td>
    
    <td>
      关闭脱敏
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        redact: true
      </code>
    </td>
    
    <td>
      保持预设的脱敏设置不变
    </td>
  </tr>
</tbody>
</table>

脱敏路径和保留事件会累加而不是替换，因此应用列出自己的路径时不会丢失预设中的脱敏路径。

配置只继承一层。如果 `evlog.preset.ts` 本身继承了配置，继续继承它会失败，并指出这两个文件：

```text [Output]
./evlog.preset extends another config, so evlog.config.ts:6 cannot extend it
→ Extend the config it extends directly, or copy the settings you need into one of the two files
```

这样每个设置距离其生效位置最多只有一个文件，`evlog config` 也会指出该文件。

`extends` 接受配置本身，也就是应用在运行时合并的值，因此不会解析路径字符串，而是拒绝它：

```text [Output]
extends in evlog.config.ts:4 is the path './evlog.preset', not a config
→ Import the config from that path as base, then set extends: base
```

### 为组织发布预设

预设软件包由一个模块和一个 `package.json` 组成。将它作为 JavaScript 发布，让每个应用都能在不编译依赖的情况下打包，并将 `evlog` 列为 peer 依赖，使预设和应用共享同一个副本：

<code-group>

```json [package.json]
{
  "name": "@acme/evlog-preset",
  "type": "module",
  "exports": "./index.mjs",
  "peerDependencies": {
    "evlog": ">=2.31.0"
  }
}
```

```js [index.mjs]
import { defineEvlog } from 'evlog'

export default defineEvlog({
  sampling: { rates: { info: 10 } },
  redact: { paths: ['user.email', 'card.number'] },
  map: { minScore: 70 },
})
```

</code-group>

每个继承它的仓库都从相同的脱敏、采样和 CI 门控开始。新增规则通过升级预设版本发布；需要例外的应用在自己的配置中写入它，`evlog config` 会将它显示在被覆盖的设置旁边。

## 在应用中使用配置

应用会执行该文件，因此 CLI 只列出的值（drain、`enrich` 函数、从 `process.env` 读取的速率）会在这里生效。`map` 和 `logs` 会被排除。配置文件如何到达应用取决于框架：

<table>
<thead>
  <tr>
    <th>
      框架
    </th>
    
    <th>
      配置如何生效
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Nuxt、Nitro、TanStack Start
    </td>
    
    <td>
      evlog 模块查找并加载它
    </td>
  </tr>
  
  <tr>
    <td>
      Eve agents
    </td>
    
    <td>
      在 <code>
        agent/hooks/evlog.ts
      </code>
      
       中使用 <code>
        defineEvlogHook(config)
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Next.js
    </td>
    
    <td>
      <code>
        createEvlog(config)
      </code>
      
       和 <code>
        createInstrumentation(toLoggerConfig(config))
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      其他框架
    </td>
    
    <td>
      在调用 <code>
        initLogger
      </code>
      
       的位置使用 <code>
        toLoggerConfig(config)
      </code>
      
      ，在注册中间件的位置使用 <code>
        toMiddlewareOptions(config)
      </code>
    </td>
  </tr>
</tbody>
</table>

### Nuxt 和 Nitro 会自动加载

模块会像 CLI 一样查找文件并将其打包进服务器，因此 `import.meta.dev` 和 `process.env` 在其中的行为与服务端代码相同。传给模块的选项会按照 `extends` 规则合并并覆盖文件：

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  modules: ['evlog/nuxt'],
  evlog: {
    sampling: { rates: { info: 100 } },
  },
})
```

无论文件如何设置，该应用都会保留所有 info 事件，文件中的其他速率仍然生效。`evlog config` 也会读取这些选项。文件名下方会注明它们覆盖了文件，并显示每个被替换设置的最终值、设置该值的行以及文件中的原值：

```text [Output]
evlog.config.ts · extends ./evlog.preset → evlog.preset.ts
nuxt.config.ts passes options to the evlog module, and they override this file

Sampling
  trace  0%      default
  debug  0%      evlog.preset.ts:4
  info   100%    nuxt.config.ts:4
         overrides 25 at evlog.config.ts:9
  warn   100%    default
  error  100%    default
  fatal  always  default
```

运行时计算的选项（例如从函数调用读取的值）会保留提示但不会列出，因为 `evlog config` 读取文件时不会执行它们。

文件中的 `drain`、`enrich` 和 `keep` 会与 `evlog:drain`、`evlog:enrich` 和 `evlog:emit:keep` hook 一起运行。已接入这些 hook 的服务器插件会继续工作，事件会到达两个 drain。使用 [`createDrainPipeline`](https://evlog.zhcndoc.com/extend/drain-pipeline) 包装的 drain 会在服务器关闭时 flush，因此文件无需 `close` hook。

在 Nuxt 中，浏览器 logger 也会从文件读取 `enabled`、`pretty` 和 `minLevel`。`nuxt.config.ts` 中的 `evlog` 键以及 `NUXT_PUBLIC_EVLOG_*` 变量仍然优先，因此 `NUXT_PUBLIC_EVLOG_MIN_LEVEL=debug` 可以降低单个部署的阈值。浏览器只从 `nuxt.config.ts` 读取 `console` 和 `transport`。

### 其他应用导入它

`toLoggerConfig` 保留 `initLogger` 接受的选项，`toMiddlewareOptions` 保留框架中间件接受的选项：

```ts [src/index.ts]
import { Hono } from 'hono'
import { initLogger, toLoggerConfig, toMiddlewareOptions } from 'evlog'
import { evlog, type EvlogVariables } from 'evlog/hono'
import config from '../evlog.config'

initLogger(toLoggerConfig(config))

const app = new Hono<EvlogVariables>()
app.use(evlog(toMiddlewareOptions(config)))
```

[`evlog init`](https://evlog.zhcndoc.com/cli/init#per-framework) 会为 Next.js、Hono、Express 和 Fastify 写入这些接线代码。Eve agent 会将配置展开到 hook 中并添加自己的选项，参见 [Eve](https://evlog.zhcndoc.com/use-cases/eve)。

[`evlog/vite`](https://evlog.zhcndoc.com/reference/vite-plugin) 插件不会读取该文件。它的自动初始化会在构建时序列化，无法携带 drain，因此请在调用 `initLogger` 的位置导入配置。

## 配置无法读取时

对于无法读取的配置，`evlog map` 和 `evlog config` 以 1 退出，`evlog logs` 以 2 退出。[`evlog doctor`](https://evlog.zhcndoc.com/cli/doctor) 会将相同错误报告为失败的 `config` 检查。每个错误都带有 CLI 目录中的代码：

<table>
<thead>
  <tr>
    <th>
      代码
    </th>
    
    <th>
      触发条件
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        cli.CONFIG_PARSE_FAILED
      </code>
    </td>
    
    <td>
      文件存在语法错误
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli.CONFIG_NO_EXPORT
      </code>
    </td>
    
    <td>
      没有默认导出对象或 <code>
        defineEvlog({ ... })
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli.CONFIG_NOT_STATIC
      </code>
    </td>
    
    <td>
      默认导出、<code>
        extends
      </code>
      
       或 <code>
        map
      </code>
      
      /<code>
        logs
      </code>
      
       值在运行时计算
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli.CONFIG_INVALID
      </code>
    </td>
    
    <td>
      设置拼写错误、类型不正确，或关闭了 <code>
        wide-event
      </code>
      
       或 <code>
        context
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli.CONFIG_EXTENDS_NOT_FOUND
      </code>
    </td>
    
    <td>
      <code>
        extends
      </code>
      
       导入没有指向文件
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli.CONFIG_EXTENDS_DEPTH
      </code>
    </td>
    
    <td>
      被继承的配置又继承了另一个配置
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli.CONFIG_EXTENDS_STRING
      </code>
    </td>
    
    <td>
      <code>
        extends
      </code>
      
       是路径字符串，而不是导入的配置
    </td>
  </tr>
</tbody>
</table>

拼写错误的键会产生错误，而不是被静默忽略：

```text [Output]
logs.limt in evlog.config.ts:14 is not a setting; expected dir, limit
→ Use a setting and a value the config reference lists
```

## 下一步

- [规则](https://evlog.zhcndoc.com/cli/rules)：`map.rules` 接受的 id，以及每项检查的要求
- [CI](https://evlog.zhcndoc.com/cli/ci)：根据分数门控 pull request

---

- [Map 规则](https://evlog.zhcndoc.com/cli/rules)
- [采样](https://evlog.zhcndoc.com/learn/sampling)


## Sitemap

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