---
title: "Nitro"
description: "一个模块涵盖 Nitro v3 和 v2。通过 `useLogger(event)` 获取请求日志记录器，并从 Nitro 插件中设置排水器和增强器。"
canonical_url: "https://evlog.zhcndoc.com/integrate/frameworks/nitro"
---
# Nitro

> 一个模块涵盖 Nitro v3 和 v2。通过 `useLogger(event)` 获取请求日志记录器，并从 Nitro 插件中设置排水器和增强器。

evlog 提供了适用于 Nitro v3 和 Nitro v2（nitropack）的模块。该模块会钩入请求生命周期，创建一个请求范围内的日志记录器，可通过 `useLogger(event)` 访问，并在响应完成时发出一个广泛事件。

<prompt :actions="["copy","cursor","claude"]" description="在我的 Nitro 应用中设置 evlog" icon="i-custom-nitro">

在我的 Nitro 应用中设置 evlog。

- 安装 evlog：pnpm add evlog
- 在 nitro.config.ts 中导入 evlog 模块（v2 使用 evlog/nitro，v3 使用 evlog/nitro/v3）
- 在应用根目录创建 evlog.config.ts，其中包含 export default defineEvlog({ service: 'my-app' })；模块会加载它，因此调用 evlog() 时无需传入选项
- 在路由处理程序中使用 useLogger(event) 构建广泛事件
- 使用 log.set() 在请求过程中累积上下文
- 使用 createError({ message, status, why, fix }) 抛出错误
- 请求完成时会自动发出广泛事件

文档：[https://www.evlog.dev/integrate/frameworks/nitro](https://www.evlog.dev/integrate/frameworks/nitro)
适配器：[https://www.evlog.dev/integrate/adapters/overview](https://www.evlog.dev/integrate/adapters/overview)

</prompt>

## 快速开始

### 1. 安装

<code-group>

```bash [pnpm]
pnpm add evlog
```

```bash [bun]
bun add evlog
```

```bash [yarn]
yarn add evlog
```

```bash [npm]
npm install evlog
```

</code-group>

### 2. 创建 evlog.config.ts

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

export default defineEvlog({
  service: 'my-app',
})
```

所有选项都位于此文件中：采样、drain、`enrich` 和路由过滤器。`npx evlog init` 会为你写入它。请参阅[配置](https://evlog.zhcndoc.com/reference/configuration)。

### 3. 添加模块

<code-group>

```typescript [nitro.config.ts (v3)]
import { defineConfig } from 'nitro'
import evlog from 'evlog/nitro/v3'

export default defineConfig({
  modules: [
    evlog(),
  ],
})
```

```typescript [nitro.config.ts (v2)]
import { defineNitroConfig } from 'nitropack/config'
import evlog from 'evlog/nitro'

export default defineNitroConfig({
  modules: [
    evlog(),
  ],
})
```

</code-group>

模块会找到并加载 `evlog.config.ts`，无需额外导入。

## 广泛事件

在请求过程中，使用 `useLogger(event)` 逐步构建上下文。evlog 会在请求完成时发出一个单一的广泛事件。

<code-group>

```typescript [routes/api/checkout.post.ts (v3)]
import { defineHandler } from 'nitro/h3'
import { useLogger } from 'evlog/nitro/v3'

export default defineHandler(async (event) => {
  const log = useLogger(event)
  const body = await readBody(event)

  log.set({ user: { id: body.userId } })
  log.set({ cart: { items: body.items.length, total: body.total } })

  return { success: true }
})
```

```typescript [routes/api/checkout.post.ts (v2)]
import { defineEventHandler, readBody } from 'h3'
import { useLogger } from 'evlog/nitro'

export default defineEventHandler(async (event) => {
  const log = useLogger(event)
  const body = await readBody(event)

  log.set({ user: { id: body.userId } })
  log.set({ cart: { items: body.items.length, total: body.total } })

  return { success: true }
})
```

</code-group>

一个请求，一条日志行，包含所有上下文信息：

```bash [终端输出]
10:23:45 INFO [my-app] POST /api/checkout 200 in 145ms
  ├─ user: id=usr_123
  ├─ cart: items=3 total=14999
  └─ requestId: a1b2c3d4-...
```

Nitro 使用 **useLogger(event)**（事件绑定的作用域），而不是 **AsyncLocalStorage**，因此 **log.fork()** 目前在这里不可用。对于 AI SDK 流式响应，evlog 会延迟发出广泛事件，直到响应正文完成，这样 `createAILogger(log)` 的元数据就会保留在同一个请求事件中。只有当代码在广泛事件实际发出后调用 `set()` 时，才会出现发出后警告，例如在非流式处理程序或后台工作中。请参阅广泛事件中的[发出后](https://evlog.zhcndoc.com/learn/wide-events#after-emit-sealing-and-background-work)。

## 错误处理

`createError` 会生成包含 `why`、`fix` 和 `link` 字段的结构化错误，帮助人类和 AI 代理理解问题所在。

<code-group>

```typescript [routes/api/payment.post.ts (v3)]
import { defineHandler } from 'nitro/h3'
import { useLogger, createError } from 'evlog/nitro/v3'

export default defineHandler(async (event) => {
  const log = useLogger(event)

  throw createError({
    status: 402,
    message: 'Payment failed',
    why: 'Card declined by issuer',
    fix: 'Try a different payment method',
  })
})
```

```typescript [routes/api/payment.post.ts (v2)]
import { defineEventHandler } from 'h3'
import { useLogger } from 'evlog/nitro'
import { createError } from 'evlog'

export default defineEventHandler(async (event) => {
  const log = useLogger(event)

  throw createError({
    status: 402,
    message: 'Payment failed',
    why: 'Card declined by issuer',
    fix: 'Try a different payment method',
  })
})
```

</code-group>

<callout color="info" icon="i-lucide-info">

在 Nitro v3 中，请从 `evlog/nitro/v3` 导入 `createError` —— 它封装了 Nitro 的错误处理机制。在 Nitro v2 中，请直接从 `evlog` 导入 `createError`。

</callout>

## 配置

请参阅 [配置参考](https://evlog.zhcndoc.com/reference/configuration)，了解所有可用选项（`enabled`、`pretty`、`silent`、`sampling` 等）。所有选项都位于 `evlog.config.ts` 中。`nitro.config.ts` 中传给 `evlog()` 的选项会按键覆盖文件中的设置。文件中的 `drain`、`enrich` 和 `keep` 永远不会被覆盖：它们会与 `evlog:*` 钩子一起运行，因此每个事件都会到达两者。

### 路由过滤

使用 `include` 和 `exclude` 控制哪些路由被记录，以及使用 `routes` 为不同的路由组分配不同的服务名称：

```typescript [evlog.config.ts]
export default defineEvlog({
  include: ['/api/**'],
  exclude: ['/api/health'],
  routes: {
    '/api/auth/**': { service: 'auth-service' },
    '/api/payment/**': { service: 'payment-service' },
  },
})
```

<callout color="warning" icon="i-lucide-alert-triangle">

**排除项优先级更高。** 如果路径同时匹配 `include` 和 `exclude`，则会被排除。

</callout>

## 排水（Drain）与增强器（Enrichers）

在 `evlog.config.ts` 中设置 `drain` 和 `enrich`：

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

export default defineEvlog({
  service: 'my-app',
  drain: createAxiomDrain(),
  enrich: (ctx) => {
    ctx.event.region = process.env.FLY_REGION
  },
})
```

文件中的缓冲 drain（例如使用 `createDrainPipeline` 构建的 drain）会在服务器关闭时刷新。如下方所示，挂接 `evlog:drain` 和 `evlog:enrich` 的 Nitro 插件仍然有效，并会与文件配置一起运行：两者都会收到每个事件。

### 排水插件

```typescript [server/plugins/evlog-drain.ts]
import type { DrainContext } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import { createDrainPipeline } from 'evlog/pipeline'

const pipeline = createDrainPipeline<DrainContext>({
  batch: { size: 50, intervalMs: 5000 },
  retry: { maxAttempts: 3 },
})
const drain = pipeline(createAxiomDrain())

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', drain)
})
```

<callout color="info" icon="i-lucide-info">

对于独立 Nitro v3，请使用 `definePlugin` 替代 `defineNitroPlugin`。

</callout>

### 增强器插件

```typescript [server/plugins/evlog-enrich.ts]
import { createUserAgentEnricher, createGeoEnricher } from 'evlog/enrichers'

const enrichers = [createUserAgentEnricher(), createGeoEnricher()]

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:enrich', (ctx) => {
    for (const enricher of enrichers) enricher(ctx)
  })
})
```

<callout color="neutral" icon="i-lucide-arrow-right">

请参阅 [适配器](https://evlog.zhcndoc.com/integrate/adapters/overview) 和 [增强器](https://evlog.zhcndoc.com/use-cases/enrichers) 文档，了解所有可用的排水器和增强器列表。

</callout>

## 采样

### 头部采样

按百分比随机保留各层级的日志。在请求完成前执行。

```typescript [evlog.config.ts]
export default defineEvlog({
  sampling: {
    rates: { info: 10, warn: 50, debug: 5 },
    keep: [
      { duration: 1000 },
      { status: 400 },
    ],
  },
})
```

每个层级都是 0 到 100 的百分比。未配置的层级默认保留 100%（保留全部）。

### 自定义尾部采样

对于超出状态、时长和路径的条件，使用 `evlog:emit:keep` 钩子：

```typescript [server/plugins/evlog-sampling.ts]
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:emit:keep', (ctx) => {
    const user = ctx.context.user as { premium?: boolean } | undefined
    if (user?.premium) ctx.shouldKeep = true
  })
})
```

<callout color="info" icon="i-lucide-info">

错误日志默认总是保留。你必须显式设置 `error: 0` 才能丢弃它们。

</callout>

## 下一步

深入了解 **Nitro** 集成：

- [广泛事件](https://evlog.zhcndoc.com/learn/wide-events): 使用上下文分层设计完整事件
- [适配器](https://evlog.zhcndoc.com/integrate/adapters/overview): 将日志发送到 Axiom、Sentry、PostHog 等
- [采样](https://evlog.zhcndoc.com/learn/sampling): 使用头部和尾部采样控制日志量
- [结构化错误](https://evlog.zhcndoc.com/learn/structured-errors): 抛出包含 `why`、`fix` 和 `link` 字段的错误


## Sitemap

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