---
title: "最佳实践"
description: "安全指南、数据消毒和生产提示。了解不应记录的内容以及如何保护敏感数据。"
canonical_url: "https://evlog.zhcndoc.com/reference/best-practices"
---
# 最佳实践

> 安全指南、数据消毒和生产提示。了解不应记录的内容以及如何保护敏感数据。

宽事件包含请求触及的每个字段，这正是它可查询的原因，也是意外泄露的密钥永久存在的原因。本页介绍哪些内容应排除、哪些内容应脱敏，以及生产环境中的成本。

## 不应记录的内容

使宽事件值得查询的累积特性，也意味着一旦某个密钥到达 `log.set`，它就会进入你的排水系统。**永远不要记录：**

<table>
<thead>
  <tr>
    <th>
      类别
    </th>
    
    <th>
      示例
    </th>
    
    <th>
      风险
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      凭证
    </td>
    
    <td>
      密码、API 密钥、令牌、密钥
    </td>
    
    <td>
      账户泄露
    </td>
  </tr>
  
  <tr>
    <td>
      支付数据
    </td>
    
    <td>
      完整卡号、CVV、银行账户
    </td>
    
    <td>
      PCI 合规违规
    </td>
  </tr>
  
  <tr>
    <td>
      个人信息（PII）
    </td>
    
    <td>
      社保号、护照号、驾驶证号
    </td>
    
    <td>
      隐私法律违规（GDPR、CCPA）
    </td>
  </tr>
  
  <tr>
    <td>
      健康数据
    </td>
    
    <td>
      医疗记录、诊断信息
    </td>
    
    <td>
      HIPAA 违规
    </td>
  </tr>
  
  <tr>
    <td>
      身份验证信息
    </td>
    
    <td>
      会话令牌、JWT、刷新令牌
    </td>
    
    <td>
      会话劫持
    </td>
  </tr>
</tbody>
</table>

<callout color="error" icon="i-lucide-shield-alert">

日志通常可被整个团队访问，并可能存储在第三方服务中。请将它们视为半公开信息。

</callout>

## 自动脱敏

保护个人身份信息（PII）的最简单方法是启用内置的自动脱敏功能：

<framework-tabs>

```typescript [Nuxt]nuxt.config.ts
evlog: {
  redact: true,
}
```

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

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

```typescript [Next.js]lib/evlog.ts
import { createEvlog } from 'evlog/next'

export const { withEvlog, useLogger, log, createError } = createEvlog({
  service: 'my-app',
  redact: true,
})
```

```typescript [SvelteKit]src/hooks.server.ts
import { createEvlogHooks } from 'evlog/sveltekit'

export const { handle, handleError } = createEvlogHooks({ redact: true })
```

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

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

```typescript [React Router]app/root.tsx
import { evlog } from 'evlog/react-router'

export const middleware: Route.MiddlewareFunction[] = [
  evlog({ redact: true }),
]
```

```typescript [Hono]src/index.ts
import { evlog } from 'evlog/hono'

app.use(evlog({ redact: true }))
```

```typescript [Express]src/index.ts
import { evlog } from 'evlog/express'

app.use(evlog({ redact: true }))
```

```typescript [Fastify]src/index.ts
import { evlog } from 'evlog/fastify'

await app.register(evlog, { redact: true })
```

```typescript [Elysia]src/index.ts
import { evlog } from 'evlog/elysia'

app.use(evlog({ redact: true }))
```

```typescript [NestJS]src/app.module.ts
import { EvlogModule } from 'evlog/nestjs'

EvlogModule.forRoot({ redact: true })
```

```typescript [oRPC]server/orpc.ts
import { withEvlog } from 'evlog/orpc'

const handler = withEvlog(new RPCHandler(router), { redact: true })
```

```typescript [Cloudflare Workers]src/worker.ts
import { withEvlog } from 'evlog/workers'

export default withEvlog(handler, { redact: true })
```

```typescript [Standalone]src/index.ts
import { initLogger } from 'evlog'

initLogger({ redact: true })
```

</framework-tabs>

这会在每个宽事件中屏蔽信用卡（`****1111`）、电子邮件（`a***@***.com`）、IP、电话号码、JWT、Bearer 令牌和 IBAN，并且会在输出到控制台以及发送到任何排水服务之前完成。有关完整的配置参考，请参阅 [Auto-Redaction](https://evlog.zhcndoc.com/learn/redaction)。

<callout color="success" icon="i-lucide-shield-check">

自动脱敏是安全网，不能替代谨慎的日志记录习惯。应始终优先选择显式字段选择，并结合 `redact: true` 实现纵深防御。

</callout>

## 在设置字段前进行消毒

### 手动字段选择

最安全的方法是显式选择要记录的字段：

<framework-tabs>

```typescript [Nuxt]server/api/user/update.post.ts
import { useLogger } from 'evlog'

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

  const body = await readBody(event)

  // ❌ 永远不要记录完整的请求体
  // log.set({ body })

  // ✅ 显式选择安全字段
  log.set({
    user: {
      id: body.id,
      email: maskEmail(body.email),
      // password: body.password ← 永远不要包含
    },
  })
})
```

```typescript [Nitro]routes/api/user/update.post.ts
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)

  // ❌ NEVER log the entire request body
  // log.set({ body })

  // ✅ Explicitly select safe fields
  log.set({
    user: {
      id: body.id,
      email: maskEmail(body.email),
      // password: body.password ← NEVER include
    },
  })
})
```

```typescript [Next.js]app/api/user/update/route.ts
import { withEvlog, useLogger } from '@/lib/evlog'

export const POST = withEvlog(async (request: Request) => {
  const log = useLogger()

  const body = await request.json()

  // ❌ NEVER log the entire request body
  // log.set({ body })

  // ✅ Explicitly select safe fields
  log.set({
    user: {
      id: body.id,
      email: maskEmail(body.email),
      // password: body.password ← NEVER include
    },
  })

  return Response.json({ ok: true })
})
```

```typescript [Hono]src/index.ts
app.post('/api/user/update', async (c) => {
  const log = c.get('log')

  const body = await c.req.json()

  // ❌ NEVER log the entire request body
  // log.set({ body })

  // ✅ Explicitly select safe fields
  log.set({
    user: {
      id: body.id,
      email: maskEmail(body.email),
      // password: body.password ← NEVER include
    },
  })

  return c.json({ ok: true })
})
```

```typescript [Express]src/index.ts
app.post('/api/user/update', async (req, res) => {
  const log = req.log

  const body = req.body

  // ❌ NEVER log the entire request body
  // log.set({ body })

  // ✅ Explicitly select safe fields
  log.set({
    user: {
      id: body.id,
      email: maskEmail(body.email),
      // password: body.password ← NEVER include
    },
  })

  res.json({ ok: true })
})
```

</framework-tabs>

### 辅助函数

创建用于消毒常见数据类型的实用函数：

<code-collapse>

```typescript [server/utils/sanitize.ts]
/** 掩码邮箱：john.doe@example.com → j***.d**@e***.com */
export function maskEmail(email: string): string {
  const [local, domain] = email.split('@')
  if (!domain) return '***'
  const [domainName, tld] = domain.split('.')
  return `${local[0]}***@${domainName[0]}***.${tld}`
}

/** 掩码银行卡号：4242424242424242 → ****4242 */
export function maskCard(card: string): string {
  return `****${card.slice(-4)}`
}

/** 截断长 ID 以提升可读性 */
export function truncateId(id: string, length = 8): string {
  if (id.length <= length) return id
  return `${id.slice(0, length)}...`
}

/** 移除对象中的敏感字段 */
export function sanitize<T extends Record<string, unknown>>(
  obj: T,
  sensitiveKeys: string[] = ['password', 'token', 'secret', 'apiKey', 'authorization']
): Partial<T> {
  const result = { ...obj }
  for (const key of sensitiveKeys) {
    if (key in result) {
      delete result[key]
    }
  }
  return result
}
```

</code-collapse>

使用示例：

<framework-tabs>

```typescript [Nuxt]server/api/checkout.post.ts
import { useLogger } from 'evlog'

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

  const { user, card } = await readBody(event)

  log.set({
    user: {
      id: user.id,
      email: maskEmail(user.email),
    },
    payment: {
      last4: maskCard(card.number),
      // ❌ 永远不要记录：卡号、CVV、过期时间
    },
  })
})
```

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

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

  const { user, card } = await readBody(event)

  log.set({
    user: {
      id: user.id,
      email: maskEmail(user.email),
    },
    payment: {
      last4: maskCard(card.number),
      // ❌ Never: number, cvv, expiry
    },
  })
})
```

```typescript [Next.js]app/api/checkout/route.ts
import { withEvlog, useLogger } from '@/lib/evlog'

export const POST = withEvlog(async (request: Request) => {
  const log = useLogger()

  const { user, card } = await request.json()

  log.set({
    user: {
      id: user.id,
      email: maskEmail(user.email),
    },
    payment: {
      last4: maskCard(card.number),
      // ❌ Never: number, cvv, expiry
    },
  })

  return Response.json({ ok: true })
})
```

```typescript [Hono]src/index.ts
app.post('/api/checkout', async (c) => {
  const log = c.get('log')

  const { user, card } = await c.req.json()

  log.set({
    user: {
      id: user.id,
      email: maskEmail(user.email),
    },
    payment: {
      last4: maskCard(card.number),
      // ❌ Never: number, cvv, expiry
    },
  })

  return c.json({ ok: true })
})
```

```typescript [Express]src/index.ts
app.post('/api/checkout', async (req, res) => {
  const log = req.log

  const { user, card } = req.body

  log.set({
    user: {
      id: user.id,
      email: maskEmail(user.email),
    },
    payment: {
      last4: maskCard(card.number),
      // ❌ Never: number, cvv, expiry
    },
  })

  res.json({ ok: true })
})
```

</framework-tabs>

### 排水钩子过滤

作为最后一道防线，在发送到外部服务前过滤敏感数据：

<framework-tabs>

```typescript [Nuxt]server/plugins/evlog.ts
const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', (ctx) => {
    // 在发送到外部服务前消毒事件
    ctx.event = deepSanitize(ctx.event) as typeof ctx.event
  })
})
```

```typescript [Nitro]server/plugins/evlog.ts
import { definePlugin } from 'nitro'
const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', (ctx) => {
    // Sanitize before sending to external service
    ctx.event = deepSanitize(ctx.event) as typeof ctx.event
  })
})
```

```typescript [Next.js]lib/evlog.ts
import { createEvlog } from 'evlog/next'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
export const { withEvlog, useLogger, log, createError } = createEvlog({
  service: 'my-app',
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
})
```

```typescript [SvelteKit]src/hooks.server.ts
import { createEvlogHooks } from 'evlog/sveltekit'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
export const { handle, handleError } = createEvlogHooks({
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
})
```

```typescript [TanStack Start]server/plugins/evlog.ts
import { definePlugin } from 'nitro'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', (ctx) => {
    // Sanitize before sending to external service
    ctx.event = deepSanitize(ctx.event) as typeof ctx.event
  })
})
```

```typescript [React Router]app/root.tsx
import { evlog } from 'evlog/react-router'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
export const middleware: Route.MiddlewareFunction[] = [
  evlog({
      drain: (ctx) => {
          // Sanitize before sending to external service
          ctx.event = deepSanitize(ctx.event) as typeof ctx.event
        },
    }),
]
```

```typescript [Hono]src/index.ts
import { evlog } from 'evlog/hono'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
app.use(evlog({
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
}))
```

```typescript [Express]src/index.ts
import { evlog } from 'evlog/express'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
app.use(evlog({
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
}))
```

```typescript [Fastify]src/index.ts
import { evlog } from 'evlog/fastify'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
await app.register(evlog, {
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
})
```

```typescript [Elysia]src/index.ts
import { evlog } from 'evlog/elysia'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
app.use(evlog({
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
}))
```

```typescript [NestJS]src/app.module.ts
import { EvlogModule } from 'evlog/nestjs'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
EvlogModule.forRoot({
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
})
```

```typescript [oRPC]server/orpc.ts
import { withEvlog } from 'evlog/orpc'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
const handler = withEvlog(new RPCHandler(router), {
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
})
```

```typescript [Cloudflare Workers]src/worker.ts
import { withEvlog } from 'evlog/workers'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
export default withEvlog(handler, {
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
})
```

```typescript [Standalone]src/index.ts
import { initLogger } from 'evlog'

const SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'authorization', 'cookie']

function deepSanitize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(deepSanitize)
  if (!value || typeof value !== 'object') return value

  const result: Record<string, unknown> = {}
  for (const [key, nested] of Object.entries(value)) {
    const name = key.toLowerCase().replace(/[-_]/g, '')
    result[key] = SENSITIVE_KEYS.some(k => name.includes(k)) ? '[REDACTED]' : deepSanitize(nested)
  }
  return result
}
initLogger({
  drain: (ctx) => {
      // Sanitize before sending to external service
      ctx.event = deepSanitize(ctx.event) as typeof ctx.event
    },
})
```

</framework-tabs>

<callout color="warning" icon="i-lucide-lightbulb">

排水钩子消毒是安全网，不能替代谨慎的日志记录习惯。始终在源头进行消毒。

</callout>

## 生产检查清单

在部署到生产环境前，请确认：

### 日志配置

- [ ] 已设置服务名称（`env.service`）
- [ ] 已配置高流量路由的采样率
- [ ] 已设置外部服务（Axis、Loki 等）的日志排水
- [ ] 生产环境中已禁用美化输出（`pretty: false`）

### 数据安全

- [ ] 已启用自动脱敏（`redact: true`）
- [ ] 日志中不包含密码或密钥
- [ ] 不记录完整的信用卡号（仅保留后 4 位）
- [ ] 不记录 API 密钥或令牌
- [ ] 个人信息已脱敏或省略（电子邮件、电话号码）
- [ ] 会话令牌未被记录
- [ ] 请求体被选择性记录（而非 `log.set({ body })`）

### 错误处理

- [ ] 错误使用 `createError()` 并包含结构化字段
- [ ] 错误信息中不包含敏感数据
- [ ] 生产环境中堆栈跟踪不暴露内部路径

## 对字段进行分组，使其保持可查询

在代码库中使用一致且分组的字段名称：

```typescript [services/checkout.ts]
// ✅ Good - grouped and descriptive
log.set({
  user: { id, plan, accountAge },
  cart: { items, total, currency },
  payment: { method, provider, last4 },
})

// ❌ 不良 — 平铺且缩写
log.set({
  uid: '123',
  n: 3,
  t: 9999,
  pm: 'card',
})
```

### 推荐字段结构

<table>
<thead>
  <tr>
    <th>
      类别
    </th>
    
    <th>
      字段
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        user
      </code>
    </td>
    
    <td>
      <code>
        id
      </code>
      
      , <code>
        plan
      </code>
      
      , <code>
        role
      </code>
      
      , <code>
        accountAge
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        request
      </code>
    </td>
    
    <td>
      <code>
        method
      </code>
      
      , <code>
        path
      </code>
      
      , <code>
        requestId
      </code>
      
      , <code>
        traceId
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cart / order
      </code>
    </td>
    
    <td>
      <code>
        items
      </code>
      
      , <code>
        total
      </code>
      
      , <code>
        currency
      </code>
      
      , <code>
        coupon
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        payment
      </code>
    </td>
    
    <td>
      <code>
        method
      </code>
      
      , <code>
        provider
      </code>
      
      , <code>
        last4
      </code>
      
      , <code>
        status
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        outcome
      </code>
    </td>
    
    <td>
      <code>
        status
      </code>
      
      , <code>
        duration
      </code>
      
      , <code>
        error
      </code>
    </td>
  </tr>
</tbody>
</table>

## 决定哪些内容在采样后保留

日志量决定你的成本，而一个无人查看的成功请求与一个失败请求的成本相同。保留所有错误，减少其余日志：

```typescript [nuxt.config.ts]
export default defineNuxtConfig({
  evlog: {
    sampling: {
      // 头部采样：每个级别按随机百分比采样
      rates: {
        info: 10,    // 10% 的成功日志
        warn: 50,    // 50% 的警告日志
        debug: 0,    // 生产环境中不记录调试日志
        error: 100,  // 始终保留错误日志
      },
      // 尾部采样：根据结果强制保留
      keep: [
        { duration: 1000 },           // 慢请求（≥1s）
        { status: 400 },              // 客户端/服务器错误
        { path: '/api/payments/**' }, // 关键路径
      ],
    },
  },
})
```

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

使用 `$production` 覆盖在开发环境保留完整日志，而在生产环境启用采样。参见 [Nuxt 框架指南](https://evlog.zhcndoc.com/integrate/frameworks/nuxt#sampling)。

</callout>

## 下一步

- [Auto-Redaction](https://evlog.zhcndoc.com/learn/redaction) - 内置的 PII 保护与智能掩码
- [Wide Events](https://evlog.zhcndoc.com/learn/wide-events) - 设计有效的宽事件
- [Structured Errors](https://evlog.zhcndoc.com/learn/structured-errors) - 错误处理模式。

---

- [适配器](https://evlog.zhcndoc.com/integrate/adapters/overview)


## Sitemap

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