---
title: "Nuxt"
description: "添加 Nuxt 模块，每个服务器路由都会发出一个宽事件。`useLogger(event)` 和 `parseError` 会自动导入，`createError` 来自 `evlog`"
canonical_url: "https://evlog.zhcndoc.com/integrate/frameworks/nuxt"
---
# Nuxt

> 添加 Nuxt 模块，每个服务器路由都会发出一个宽事件。`useLogger(event)` 和 `parseError` 会自动导入，`createError` 来自 `evlog`

evlog 提供了一流的 Nuxt 模块，并自动导入 `useLogger` 和 `parseError`。将其添加到配置中，即可无需任何样板代码开始记录日志。

<prompt :actions="["copy","cursor","claude"]" description="在我的 Nuxt 应用中设置 evlog" icon="i-simple-icons-nuxtdotjs">

在我的 Nuxt 应用中设置 evlog，支持宽事件和结构化错误。

- 安装 evlog：pnpm add evlog
- 将 'evlog/nuxt' 添加到 nuxt.config.ts 的 modules 中
- 在应用根目录创建 evlog.config.ts，其中包含 export default defineEvlog({ service: 'my-app' })；模块会加载它
- useLogger 和 parseError 会自动导入，从 'evlog' 导入 createError
- 使用 useLogger(event) 和 log.set() 创建一个 server/api 路由来构建广泛事件
- 使用 createError({ message, status, why, fix }) 抛出错误，从 'evlog' 导入
- 每个请求完成时都会自动发出广泛事件

文档：[https://www.evlog.dev/integrate/frameworks/nuxt](https://www.evlog.dev/integrate/frameworks/nuxt)
适配器：[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. 添加模块

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

就这样。`useLogger` 和 `parseError` 会自动导入。`createError` 从 `evlog` 导入。
模块会找到并加载 `evlog.config.ts`，无需额外导入。`useLogger` 和 `parseError` 会自动导入。`createError` 从 `evlog` 导入。

## 宽事件

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

```typescript [server/api/checkout.post.ts]
export default defineEventHandler(async (event) => {
  const log = useLogger(event)
  const body = await readBody(event)

  log.set({ user: { id: body.userId, plan: 'enterprise' } })

  const cart = await db.findCart(body.cartId)
  log.set({ cart: { items: cart.items.length, total: cart.total } })

  const payment = await processPayment(cart)
  log.set({ payment: { method: payment.method, cardLast4: payment.last4 } })

  return { success: true, orderId: payment.orderId }
})
```

请提供需要本地化的 markdown/mdx 文档内容。我会按你的规则直接翻译成简体中文，并保持原有格式不变。

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

## 错误处理

`createError` 会生成包含 `why`、`fix` 和 `link` 字段的结构化错误，帮助人类和 AI 代理了解发生了什么。请从 `evlog` 导入它：服务器路由中直接使用的 `createError` 属于 h3，而 h3 会丢弃它不了解的字段。

```typescript [server/api/payment/process.post.ts]
import { createError } from 'evlog'

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

  log.set({ payment: { amount: body.amount } })

  if (body.amount <= 0) {
    throw createError({
      status: 400,
      message: 'Invalid payment amount',
      why: '金额必须是正数',
      fix: '传入一个以分为单位的正整数（例如 4999 表示 $49.99）',
      link: 'https://docs.example.com/api/payments#amount',
    })
  }

  return { success: true }
})
```

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

Nuxt 的错误处理程序会自动捕获 `EvlogError`，并返回包含 `why`、`fix` 和 `link` 字段的结构化 JSON 响应。使用 h3 的 `createError` 抛出的错误会保留其 `data` 负载，与不使用该模块时一样

</callout>

## 配置

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

请参阅 [配置参考](https://evlog.zhcndoc.com/reference/configuration) 以查看共享选项的完整列表（`enabled`、`pretty`、`silent`、`sampling`、中间件选项等）。

</callout>

在 `evlog.config.ts` 中设置选项。`nuxt.config.ts` 中的 `evlog` 键接受相同的选项，并按键覆盖文件中的设置。文件中的 `drain`、`enrich` 和 `keep` 永远不会被覆盖：它们会与 `evlog:*` 钩子一起运行，因此每个事件都会到达两者。

除非 `evlog` 键或 `NUXT_PUBLIC_EVLOG_*` 设置了 `enabled`、`pretty` 和 `minLevel`，否则浏览器日志记录器会从文件中读取这些选项。`console` 和 `transport` 只来自 `nuxt.config.ts`。

下表使用文件中的键；在 `evlog.config.ts` 中，你可以将 `service` 和 `environment` 写在顶层，而不是放在 `env` 下。

<table>
<thead>
  <tr>
    <th>
      选项
    </th>
    
    <th>
      类型
    </th>
    
    <th>
      默认值
    </th>
    
    <th>
      描述
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        enabled
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      全局启用或禁用所有日志记录。当值为 <code>
        false
      </code>
      
       时，所有操作都不执行任何操作
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        console
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      启用或禁用浏览器控制台输出
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        env.service
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'app'
      </code>
    </td>
    
    <td>
      日志中显示的服务名称
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        env.environment
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      自动检测
    </td>
    
    <td>
      环境名称
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        include
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      要记录的路由模式。支持 glob（<code>
        /api/**
      </code>
      
      ）
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        exclude
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      要排除的路由模式。排除项优先
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        routes
      </code>
    </td>
    
    <td>
      <code>
        Record<string, RouteConfig>
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      特定路由的服务配置
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pretty
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      开发环境中为 <code>
        true
      </code>
    </td>
    
    <td>
      使用树形格式进行美化输出
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dev
      </code>
    </td>
    
    <td>
      <code>
        'evlog' | 'nitro' | 'both' | object
      </code>
    </td>
    
    <td>
      美化开发环境中为 <code>
        'evlog'
      </code>
    </td>
    
    <td>
      开发终端预设，或 <code>
        { frameworkOverlay, prettyError }
      </code>
      
       —— 请参阅<a href="https://evlog.zhcndoc.com/learn/structured-errors#development-terminal-output">
        配置——开发终端输出
      </a>
    </td>
  </tr>
</tbody>
</table>

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

**开发终端预设：**`'evlog'`（默认）提供一个简洁的信号，仅显示 evlog 堆栈。`'nitro'` 提供宽事件上下文和 Nitro Youch 堆栈（evlog 仅打印 Why/Fix）。`'both'` 提供完整的 evlog 块和 Nitro 覆盖层。使用 `pretty: false` 时，设置 `dev: { frameworkOverlay: false }` 可在记录 JSON 的同时抑制 Nitro

</callout>

| `silent` | `boolean` | `false` | 抑制控制台输出。事件仍会被构建、采样并清空。适用于基于 stdout 的平台 |
| `sampling.rates` | `object` | `undefined` | 按日志级别设置的头部采样率（0-100%） |
| `sampling.keep` | `array` | `undefined` | 尾部采样条件，用于强制保留日志 |
| `transport.enabled` | `boolean` | `false` | 启用客户端到服务端的日志传输 |
| `transport.endpoint` | `string` | `'/api/_evlog/ingest'` | 传输端点 |

## 路由过滤

使用 `include` 和 `exclude` 控制记录哪些路由：

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

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

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

</callout>

### 基于路由的服务名称

为不同路由组分配不同的服务名称：

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

## 排水与增强器

在 `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)
})
```

### 增强器插件

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

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

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 [nuxt.config.ts]
export default defineNuxtConfig({
  modules: ['evlog/nuxt'],
  evlog: {
    sampling: {
      rates: {
        info: 10,
        warn: 50,
        debug: 5,
        error: 100,
      },
    },
  },
})
```

每个级别都是一个 0 到 100 的百分比。未配置的级别默认保留 100%（保留全部）。错误级别默认为 100%，即使配置了其他级别。

### 尾部采样

在请求完成后进行评估，根据特定条件强制保留日志，无论头部采样如何。

```typescript [nuxt.config.ts]
export default defineNuxtConfig({
  modules: ['evlog/nuxt'],
  evlog: {
    sampling: {
      rates: { info: 10 },
      keep: [
        { duration: 1000 },
        { status: 400 },
        { path: '/api/critical/**' },
      ],
    },
  },
})
```

### 自定义尾部采样

对于超出状态、持续时间和路径的条件，使用 `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>

## 客户端传输

将浏览器日志发送到服务器进行处理和排出，与服务器端事件一起处理。

```typescript [nuxt.config.ts]
export default defineNuxtConfig({
  modules: ['evlog/nuxt'],
  evlog: {
    transport: {
      enabled: true,
      endpoint: '/api/_evlog/ingest',
    },
  },
})
```

### 工作原理

1. 客户端调用 `log.info({ action: 'click', button: 'submit' })`
2. 日志通过 POST 发送到 `/api/_evlog/ingest`
3. 服务器使用环境上下文进行增强
4. 触发 `evlog:drain` 钩子，`source: 'client'`
5. 外部服务接收日志

### 客户端身份

使用 `setIdentity` 为每个客户端日志附加用户上下文：

```typescript [Nuxt（自动导入）]
// 登录后
setIdentity({ userId: 'usr_123', orgId: 'org_456' })

log.info({ action: 'checkout' })
// -> { userId: 'usr_123', orgId: 'org_456', action: 'checkout', ... }

// 登出后
clearIdentity()
```

### 与身份验证同步身份

使用路由中间件保持身份与认证状态同步：

```typescript [middleware/identity.global.ts]
export default defineNuxtRouteMiddleware(() => {
  const { user } = useAuth()

  if (user.value) {
    setIdentity({ userId: user.value.id, email: user.value.email })
  } else {
    clearIdentity()
  }
})
```

## 生产环境建议

使用 Nuxt 的 `$production` 覆盖，在开发环境中保持完整日志记录，同时在生产环境中进行采样并禁用控制台输出：

```typescript [nuxt.config.ts]
export default defineNuxtConfig({
  modules: ['evlog/nuxt'],
  evlog: {
    env: { service: 'my-app' },
  },
  $production: {
    evlog: {
      console: false,
      sampling: {
        rates: { info: 10, warn: 50, debug: 0 },
        keep: [{ duration: 1000 }, { status: 400 }],
      },
    },
  },
})
```

## 后续步骤

深入你的 **Nuxt** 集成：

- [宽事件](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.
