框架
Nuxt
自动宽事件、结构化错误、排水适配器、增强器、尾部采样,以及 Nuxt 应用程序中的客户端传输。
evlog 为 Nuxt 提供一流的模块支持,包含自动导入的 useLogger、createError 和 parseError。将其添加到配置中即可零样板文件开始记录日志。
提示
在 Nuxt 应用中设置 evlog,开启宽事件和结构化错误。
- 安装 evlog:pnpm add evlog
- 在 nuxt.config.ts 的 modules 中添加 'evlog/nuxt'
- 设置 evlog.env.service 为你的应用名称
- useLogger、createError 和 parseError 已自动导入
- 创建一个服务器 API 路由,使用 useLogger(event) 和 log.set() 构建宽事件
- 使用 createError({ message, status, why, fix }) 抛出错误
- 宽事件会在每个请求完成时自动发出
文档:https://www.evlog.dev/frameworks/nuxt
适配器:https://www.evlog.dev/adapters
快速开始
1. 安装
pnpm add evlog
npm install evlog
yarn add evlog
bun add evlog
2. 添加模块
nuxt.config.ts
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
env: {
service: 'my-app',
},
},
})
就这样。useLogger、createError 和 parseError 已经自动导入。
宽事件
使用 useLogger(event) 在请求过程中逐步构建上下文。evlog 在请求完成时发出单个宽事件。
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 }
})
一个请求,一条包含所有上下文的日志:
终端输出
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 代理理解问题所在。
server/api/payment/process.post.ts
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: 'The amount must be a positive number',
fix: 'Pass a positive integer in cents (e.g. 4999 for $49.99)',
link: 'https://docs.example.com/api/payments#amount',
})
}
return { success: true }
})
Nuxt 的错误处理器会自动捕获
EvlogError 并返回包含 why、fix 和 link 字段的结构化 JSON 响应。配置
所有选项均在 nuxt.config.ts 中的 evlog 键下设置:
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
enabled | boolean | true | 全局启用/禁用所有日志记录。当为 false 时,所有操作都变为无操作 |
console | boolean | true | 启用/禁用浏览器控制台输出 |
env.service | string | 'app' | 日志中显示的服务名称 |
env.environment | string | 自动检测 | 环境名称 |
include | string[] | undefined | 要记录路由的模式。支持通配符(/api/**) |
exclude | string[] | undefined | 要排除的路由模式。排除项优先级更高 |
routes | Record<string, RouteConfig> | undefined | 路由特定服务配置 |
pretty | boolean | 开发环境下为 true | 使用树形格式美化输出 |
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 控制记录哪些路由:
nuxt.config.ts
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
include: ['/api/**', '/auth/**'],
exclude: [
'/api/_nuxt_icon/**',
'/api/_content/**',
'/api/health',
],
},
})
排除项优先级更高。 如果路径同时匹配
include 和 exclude,则会被排除。基于路由的服务名称
为不同路由组分配不同的服务名称:
nuxt.config.ts
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
env: { service: 'default-service' },
routes: {
'/api/auth/**': { service: 'auth-service' },
'/api/payment/**': { service: 'payment-service' },
'/api/booking/**': { service: 'booking-service' },
},
},
})
排水与增强器
使用 Nitro 插件钩子将日志发送到外部服务并使用附加上下文进行增强。
排水插件
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)
})
增强器插件
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)
})
})
采样
头部采样
按百分比随机保留每个级别的日志。在请求完成前运行。
nuxt.config.ts
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
sampling: {
rates: {
info: 10,
warn: 50,
debug: 5,
error: 100,
},
},
},
})
每个级别都是一个 0 到 100 的百分比。未配置的级别默认保留 100%(保留全部)。错误级别默认为 100%,即使配置了其他级别。
尾部采样
在请求完成后进行评估,根据特定条件强制保留日志,无论头部采样如何。
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 钩子:
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
}
})
})
错误默认始终保留。你必须显式设置
error: 0 才能丢弃它们。客户端传输
将浏览器日志发送到服务器进行处理和排出,与服务器端事件一起处理。
nuxt.config.ts
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
transport: {
enabled: true,
endpoint: '/api/_evlog/ingest',
},
},
})
工作原理
- 客户端调用
log.info({ action: 'click', button: 'submit' }) - 日志通过 POST 发送到
/api/_evlog/ingest - 服务器使用环境上下文进行增强
- 触发
evlog:drain钩子,source: 'client' - 外部服务接收日志
客户端身份
使用 setIdentity 为每个客户端日志附加用户上下文:
Nuxt(自动导入)
// 登录后
setIdentity({ userId: 'usr_123', orgId: 'org_456' })
log.info({ action: 'checkout' })
// -> { userId: 'usr_123', orgId: 'org_456', action: 'checkout', ... }
// 登出后
clearIdentity()
与身份验证同步身份
使用路由中间件保持身份与认证状态同步:
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 覆盖,在开发环境中保持完整日志记录,同时在生产环境中进行采样并禁用控制台输出:
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 集成: